From a2773226633e0be5d3567b5145e440c83cfdb9ea Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 23 Feb 2026 21:43:35 +0100 Subject: [PATCH 01/18] feat: update @tanstack/store to v9 --- .../react/basic-external-state/package.json | 2 +- .../react/basic-external-store/package.json | 2 +- .../react/basic-external-store/src/main.tsx | 23 ++-- examples/react/composable-tables/package.json | 2 +- examples/react/pagination/package.json | 2 +- examples/react/row-selection/package.json | 2 +- .../react/with-tanstack-query/package.json | 2 +- .../react/with-tanstack-query/src/main.tsx | 4 +- packages/angular-table/package.json | 2 +- packages/angular-table/src/injectTable.ts | 9 -- packages/preact-table/package.json | 2 +- packages/preact-table/src/useTable.ts | 6 - packages/react-table/package.json | 2 +- packages/react-table/src/useTable.ts | 6 - packages/svelte-table/package.json | 2 +- packages/table-core/package.json | 2 +- .../src/core/table/constructTable.ts | 34 +++--- .../src/core/table/coreTablesFeature.types.ts | 4 +- .../src/core/table/coreTablesFeature.utils.ts | 2 +- packages/table-core/src/types/Table.ts | 4 +- packages/vue-table/package.json | 2 +- packages/vue-table/src/useTable.ts | 2 +- pnpm-lock.yaml | 115 +++++++++++------- 23 files changed, 114 insertions(+), 119 deletions(-) diff --git a/examples/react/basic-external-state/package.json b/examples/react/basic-external-state/package.json index d11f9b75b8..16d481f42e 100644 --- a/examples/react/basic-external-state/package.json +++ b/examples/react/basic-external-state/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.2.0", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/basic-external-store/package.json b/examples/react/basic-external-store/package.json index 65767f6edb..82fcaa44ec 100644 --- a/examples/react/basic-external-store/package.json +++ b/examples/react/basic-external-store/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.2.0", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/basic-external-store/src/main.tsx b/examples/react/basic-external-store/src/main.tsx index 8059013a3d..2b5f11d5e9 100644 --- a/examples/react/basic-external-store/src/main.tsx +++ b/examples/react/basic-external-store/src/main.tsx @@ -1,7 +1,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' import './index.css' -import { Store, useStore } from '@tanstack/react-store' +import { createStore, useStore } from '@tanstack/react-store' import { createColumnHelper, createPaginatedRowModel, @@ -60,18 +60,17 @@ function App() { const rerender = React.useReducer(() => ({}), {})[1] // create our own TanStack Store in our own scope (This could just be a global store if defined outside of this component) - const [myTableStore] = React.useState( - () => - new Store( - getInitialTableState( - _features, // get default initial state from features - // custom initial state - { - sorting: [], - pagination: { pageIndex: 0, pageSize: 10 }, - }, - ), + const [myTableStore] = React.useState(() => + createStore( + getInitialTableState( + _features, // get default initial state from features + // custom initial state + { + sorting: [], + pagination: { pageIndex: 0, pageSize: 10 }, + }, ), + ), ) // Subscribe to store state for reactive updates, custom selector available too diff --git a/examples/react/composable-tables/package.json b/examples/react/composable-tables/package.json index 12e8d86f52..155033b8b7 100644 --- a/examples/react/composable-tables/package.json +++ b/examples/react/composable-tables/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.2.0", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/pagination/package.json b/examples/react/pagination/package.json index 277befeb23..fc5538b221 100644 --- a/examples/react/pagination/package.json +++ b/examples/react/pagination/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.2.0", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/row-selection/package.json b/examples/react/row-selection/package.json index 8c6df93216..3446205488 100644 --- a/examples/react/row-selection/package.json +++ b/examples/react/row-selection/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.2.0", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/with-tanstack-query/package.json b/examples/react/with-tanstack-query/package.json index 7b3e530736..e91d9b4310 100644 --- a/examples/react/with-tanstack-query/package.json +++ b/examples/react/with-tanstack-query/package.json @@ -13,7 +13,7 @@ "dependencies": { "@faker-js/faker": "^10.2.0", "@tanstack/react-query": "^5.90.20", - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/react-table": "^9.0.0-alpha.11", "react": "^19.2.4", "react-dom": "^19.2.4" diff --git a/examples/react/with-tanstack-query/src/main.tsx b/examples/react/with-tanstack-query/src/main.tsx index 3ad4ac0dc9..382b8a378b 100644 --- a/examples/react/with-tanstack-query/src/main.tsx +++ b/examples/react/with-tanstack-query/src/main.tsx @@ -6,7 +6,7 @@ import { keepPreviousData, useQuery, } from '@tanstack/react-query' -import { Store, useStore } from '@tanstack/react-store' +import { createStore, useStore } from '@tanstack/react-store' import './index.css' import { createColumnHelper, @@ -49,7 +49,7 @@ const columns = columnHelper.columns([ }), ]) -const myTableStore = new Store( +const myTableStore = createStore( getInitialTableState(_features, { pagination: { pageIndex: 0, pageSize: 10 }, }), diff --git a/packages/angular-table/package.json b/packages/angular-table/package.json index fc49bfcfb6..b400afd33b 100644 --- a/packages/angular-table/package.json +++ b/packages/angular-table/package.json @@ -51,7 +51,7 @@ "test:types": "tsc && vitest --typecheck" }, "dependencies": { - "@tanstack/angular-store": "^0.8.0", + "@tanstack/angular-store": "^0.9.1", "@tanstack/table-core": "workspace:*", "tslib": "^2.8.1" }, diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index 893b099aa6..c1cbc5d8fd 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -2,7 +2,6 @@ import { Injector, assertInInjectionContext, computed, - effect, inject, untracked, } from '@angular/core' @@ -134,14 +133,6 @@ export function injectTable< return result }) - effect( - (onCleanup) => { - const cleanup = table.store.mount() - onCleanup(() => cleanup()) - }, - { injector }, - ) - const tableState = injectStore( table.store, (state: TableState) => state, diff --git a/packages/preact-table/package.json b/packages/preact-table/package.json index 10b42a25ff..27f7c10b2b 100644 --- a/packages/preact-table/package.json +++ b/packages/preact-table/package.json @@ -51,7 +51,7 @@ "build": "vite build" }, "dependencies": { - "@tanstack/preact-store": "^0.10.1", + "@tanstack/preact-store": "^0.11.1", "@tanstack/table-core": "workspace:*" }, "devDependencies": { diff --git a/packages/preact-table/src/useTable.ts b/packages/preact-table/src/useTable.ts index f310e660fc..cfbc4e630a 100644 --- a/packages/preact-table/src/useTable.ts +++ b/packages/preact-table/src/useTable.ts @@ -107,12 +107,6 @@ export function useTable< ...tableOptions, })) - // Mount the derived store to register it on the dependency graph - useIsomorphicLayoutEffect(() => { - const cleanup = table.store.mount() - return cleanup - }, [table]) - useIsomorphicLayoutEffect(() => { // prevent race condition between table.setOptions and table.baseStore.setState queueMicrotask(() => { diff --git a/packages/react-table/package.json b/packages/react-table/package.json index 770f7b7a20..f42fe2725a 100644 --- a/packages/react-table/package.json +++ b/packages/react-table/package.json @@ -51,7 +51,7 @@ "build": "vite build" }, "dependencies": { - "@tanstack/react-store": "^0.8.0", + "@tanstack/react-store": "^0.9.1", "@tanstack/table-core": "workspace:*" }, "devDependencies": { diff --git a/packages/react-table/src/useTable.ts b/packages/react-table/src/useTable.ts index 1d0c48ac07..45af500ffd 100644 --- a/packages/react-table/src/useTable.ts +++ b/packages/react-table/src/useTable.ts @@ -108,12 +108,6 @@ export function useTable< ...tableOptions, })) - // Mount the derived store to register it on the dependency graph - useIsomorphicLayoutEffect(() => { - const cleanup = table.store.mount() - return cleanup - }, [table]) - useIsomorphicLayoutEffect(() => { // prevent race condition between table.setOptions and table.baseStore.setState queueMicrotask(() => { diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index bb6fa1d189..f517dcc186 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -47,7 +47,7 @@ "build": "svelte-package --input ./src --output ./dist" }, "dependencies": { - "@tanstack/svelte-store": "^0.9.0", + "@tanstack/svelte-store": "^0.10.1", "@tanstack/table-core": "workspace:*" }, "devDependencies": { diff --git a/packages/table-core/package.json b/packages/table-core/package.json index 7226450407..13298d7f9e 100644 --- a/packages/table-core/package.json +++ b/packages/table-core/package.json @@ -55,6 +55,6 @@ "build": "vite build" }, "dependencies": { - "@tanstack/store": "^0.8.0" + "@tanstack/store": "^0.9.1" } } diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index a4b4cdb350..daa80f34f7 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -1,6 +1,6 @@ -import { Derived, Store } from '@tanstack/store' -import {} from '../../utils' +import { createStore } from '@tanstack/store' import { coreFeatures } from '../coreFeatures' +import type { Store } from '@tanstack/store' import type { RowData } from '../../types/type-utils' import type { TableFeature, TableFeatures } from '../../types/TableFeatures' import type { Table, Table_Internal } from '../../types/Table' @@ -23,7 +23,7 @@ export function createTableStore( features: TFeatures, initialState: Partial> | undefined = {}, ): Store> { - return new Store(getInitialTableState(features, initialState)) + return createStore(getInitialTableState(features, initialState)) } export function constructTable< @@ -52,20 +52,14 @@ export function constructTable< table.options.initialState, ) - table.baseStore = - table.options.store ?? (new Store(table.initialState) as any) - - // @ts-ignore - complex TFeatures type inference does not work with Derived - table.store = new Derived({ - deps: [table.baseStore], - fn: ({ currDepVals }) => { - const baseState = currDepVals[0] - // Merge base state with user-provided external state (table.options.state takes precedence) - return { - ...baseState, - ...(table.options.state ?? {}), - } as TableState - }, + table.baseStore = table.options.store ?? createStore(table.initialState) + + table.store = createStore(() => { + const state = table.baseStore.get() + return { + ...state, + ...(table.options.state ?? {}), + } }) if ( @@ -78,11 +72,11 @@ export function constructTable< console.log( `Constructing Table Instance - + Features: ${features.join('\n ')} - + Row Models: ${rowModels.length ? rowModels.join('\n ') : '(none)'} - + States: ${states.join('\n ')}`, ) } diff --git a/packages/table-core/src/core/table/coreTablesFeature.types.ts b/packages/table-core/src/core/table/coreTablesFeature.types.ts index a8627c2660..53e88695f9 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.types.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.types.ts @@ -1,4 +1,4 @@ -import type { Derived, Store } from '@tanstack/store' +import type { ReadonlyStore, Store } from '@tanstack/store' import type { CoreFeatures } from '../coreFeatures' import type { RowModelFns } from '../../types/RowModelFns' import type { RowData, Updater } from '../../types/type-utils' @@ -105,7 +105,7 @@ export interface Table_CoreProperties< /** * Where the table state is stored. */ - store: Derived, [Store>]> + store: ReadonlyStore> } export interface Table_Table< diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 40595457ee..85c2cd7869 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -8,7 +8,7 @@ export function table_reset< TFeatures extends TableFeatures, TData extends RowData, >(table: Table_Internal): void { - table.baseStore.setState(structuredClone(table.initialState)) + table.baseStore.setState(() => structuredClone(table.initialState)) } export function table_mergeOptions< diff --git a/packages/table-core/src/types/Table.ts b/packages/table-core/src/types/Table.ts index 943bfce3c1..075ff363c7 100644 --- a/packages/table-core/src/types/Table.ts +++ b/packages/table-core/src/types/Table.ts @@ -1,4 +1,4 @@ -import type { Derived, Store } from '@tanstack/store' +import type { ReadonlyStore, Store } from '@tanstack/store' import type { Table_ColumnFaceting } from '../features/column-faceting/columnFacetingFeature.types' import type { Table_ColumnResizing } from '../features/column-resizing/columnResizingFeature.types' import type { Table_ColumnFiltering } from '../features/column-filtering/columnFilteringFeature.types' @@ -121,5 +121,5 @@ export type Table_Internal< } initialState: TableState_All baseStore: Store - store: Derived + store: ReadonlyStore } diff --git a/packages/vue-table/package.json b/packages/vue-table/package.json index 01eebed33c..e638670040 100644 --- a/packages/vue-table/package.json +++ b/packages/vue-table/package.json @@ -50,7 +50,7 @@ }, "dependencies": { "@tanstack/table-core": "workspace:*", - "@tanstack/vue-store": "^0.8.0" + "@tanstack/vue-store": "^0.9.1" }, "devDependencies": { "@vitejs/plugin-vue": "^6.0.3", diff --git a/packages/vue-table/src/useTable.ts b/packages/vue-table/src/useTable.ts index 77802eb19e..b4d851c878 100644 --- a/packages/vue-table/src/useTable.ts +++ b/packages/vue-table/src/useTable.ts @@ -116,7 +116,7 @@ export function useTable< watch( () => tableOptions.data, () => { - table.store.setState((prev: TableState) => ({ + table.baseStore.setState((prev: TableState) => ({ ...prev, data: unref(tableOptions.data), })) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eddd6dbdbe..56d6f8737f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1180,8 +1180,8 @@ importers: specifier: ^10.2.0 version: 10.2.0 '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -1217,8 +1217,8 @@ importers: specifier: ^10.2.0 version: 10.2.0 '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -1745,8 +1745,8 @@ importers: specifier: ^10.2.0 version: 10.2.0 '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -2092,8 +2092,8 @@ importers: specifier: ^10.2.0 version: 10.2.0 '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -2209,8 +2209,8 @@ importers: specifier: ^10.2.0 version: 10.2.0 '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -2551,8 +2551,8 @@ importers: specifier: ^5.90.20 version: 5.90.20(react@19.2.4) '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-table': specifier: ^9.0.0-alpha.11 version: link:../../../packages/react-table @@ -3463,8 +3463,8 @@ importers: packages/angular-table: dependencies: '@tanstack/angular-store': - specifier: ^0.8.0 - version: 0.8.0(@angular/common@21.1.1(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0)) + specifier: ^0.9.1 + version: 0.9.1(@angular/common@21.1.1(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0)) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3510,8 +3510,8 @@ importers: packages/preact-table: dependencies: '@tanstack/preact-store': - specifier: ^0.10.1 - version: 0.10.1(preact@10.28.2) + specifier: ^0.11.1 + version: 0.11.1(preact@10.28.2) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3526,8 +3526,8 @@ importers: packages/react-table: dependencies: '@tanstack/react-store': - specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^0.9.1 + version: 0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3589,7 +3589,7 @@ importers: dependencies: '@tanstack/solid-store': specifier: ^0.8.0 - version: 0.8.0(solid-js@1.9.11) + version: 0.8.1(solid-js@1.9.11) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3604,8 +3604,8 @@ importers: packages/svelte-table: dependencies: '@tanstack/svelte-store': - specifier: ^0.9.0 - version: 0.9.0(svelte@5.48.5) + specifier: ^0.10.1 + version: 0.10.1(svelte@5.48.5) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3629,8 +3629,8 @@ importers: packages/table-core: dependencies: '@tanstack/store': - specifier: ^0.8.0 - version: 0.8.0 + specifier: ^0.9.1 + version: 0.9.1 packages/table-devtools: dependencies: @@ -3666,8 +3666,8 @@ importers: specifier: workspace:* version: link:../table-core '@tanstack/vue-store': - specifier: ^0.8.0 - version: 0.8.0(vue@3.5.27(typescript@5.9.3)) + specifier: ^0.9.1 + version: 0.9.1(vue@3.5.27(typescript@5.9.3)) devDependencies: '@vitejs/plugin-vue': specifier: ^6.0.3 @@ -7088,8 +7088,8 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 - '@tanstack/angular-store@0.8.0': - resolution: {integrity: sha512-6A5SdXmpLXh6ZULdu9r3aekCuz3nCLgHd8xbbmEcYKcEePTAsBQhRCNolM9REqtyxVqXNgoU2pQws56cW9x0+w==} + '@tanstack/angular-store@0.9.1': + resolution: {integrity: sha512-XdrVBZperSRulkk8kLsPP/apNZQZwAWvNeO6PMb+kRv7iOXAzxaIK2LQTZFLtfT1QgQZFeEqU8klJcdcuG6JcQ==} peerDependencies: '@angular/common': '>=19.0.0' '@angular/core': '>=19.0.0' @@ -7161,8 +7161,8 @@ packages: resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} engines: {node: '>=18'} - '@tanstack/preact-store@0.10.1': - resolution: {integrity: sha512-LLwm4vd38kz/db8Af8J0KQd4h6vapS8QW2r0iE6jJ3x33GQeXGsi/CGTUe5QBhEP1RnXgUaAlFNnmusfXloreQ==} + '@tanstack/preact-store@0.11.1': + resolution: {integrity: sha512-dbaXYZX2YVtxVRcGJsSUCTH8wfAB+xFkKfnRGyEI1Z4s4js6HHbUK7GtMTTo6MCyNHYZqDI1w49Dj8Gj+IbwEA==} peerDependencies: preact: ^10.0.0 @@ -7209,6 +7209,12 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-store@0.9.1': + resolution: {integrity: sha512-YzJLnRvy5lIEFTLWBAZmcOjK3+2AepnBv/sr6NZmiqJvq7zTQggyK99Gw8fqYdMdHPQWXjz0epFKJXC+9V2xDA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-virtual@3.13.18': resolution: {integrity: sha512-dZkhyfahpvlaV0rIKnvQiVoWPyURppl6w4m9IwMDpuIjcJ1sD9YGWrt0wISvgU7ewACXx2Ct46WPgI6qAD4v6A==} peerDependencies: @@ -7252,8 +7258,8 @@ packages: resolution: {integrity: sha512-Lvq5VnH9Rtqci0urHENMMlyswN5fySvIANclS7cUq2xOr5Cc9QfPpwctZ3Bi1X+MibKIcXplTAixIYDFyYquQg==} engines: {node: '>=12'} - '@tanstack/solid-store@0.8.0': - resolution: {integrity: sha512-JwqTedbxyOGw7mfmdGkB0RGgefRCw/tNauc8tlMcaS1mV5wTFT8c1KIB3LgttuHaanMJEBeqQJ7bc/R0WTP1fA==} + '@tanstack/solid-store@0.8.1': + resolution: {integrity: sha512-1p4TTJGIZJ2J7130aTo7oWfHVRSCd9DxLP3HzcDMnzn56pz8krlyBEzsE+z/sHGXP0EC/JjT02fgj2L9+fmf8Q==} peerDependencies: solid-js: ^1.6.0 @@ -7263,8 +7269,14 @@ packages: '@tanstack/store@0.8.0': resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} - '@tanstack/svelte-store@0.9.0': - resolution: {integrity: sha512-FMnsMCu5nJVkinhuXkiFJvTE4yPXlEV1O5GZzAfnCSDXTunQIwWbGOKx2+oH+JThcKpnurGFO5xc2QyluInRJA==} + '@tanstack/store@0.8.1': + resolution: {integrity: sha512-PtOisLjUZPz5VyPRSCGjNOlwTvabdTBQ2K80DpVL1chGVr35WRxfeavAPdNq6pm/t7F8GhoR2qtmkkqtCEtHYw==} + + '@tanstack/store@0.9.1': + resolution: {integrity: sha512-+qcNkOy0N1qSGsP7omVCW0SDrXtaDcycPqBDE726yryiA5eTDFpjBReaYjghVJwNf1pcPMyzIwTGlYjCSQR0Fg==} + + '@tanstack/svelte-store@0.10.1': + resolution: {integrity: sha512-heeyV9bZQHbEJyJ7oWegQXmcyA8NSPP58JsZgRpvf8+lwEMfX+MW1IvPJbGZqmH+poULAz7DDxjC4JEe7l57LA==} peerDependencies: svelte: ^5.0.0 @@ -7285,8 +7297,8 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 - '@tanstack/vue-store@0.8.0': - resolution: {integrity: sha512-YLsinYboBLIjNkxDpAn1ydaMS35dKq3M3a788JRCJi4/stWcN7Swp0pxxJ+p0IwKSY4tBXx7vMz22OYWQ1QsUQ==} + '@tanstack/vue-store@0.9.1': + resolution: {integrity: sha512-mXXZzPWom656MExX2gG1fqopJhToDbqGEl98WtJ5/hyouQHtQXiAgtsPNLzUcVcwU9okM/OCWv7QAgXf6C5ziQ==} peerDependencies: '@vue/composition-api': ^1.2.1 vue: ^2.5.0 || ^3.0.0 @@ -15629,11 +15641,11 @@ snapshots: tailwindcss: 4.1.18 vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2) - '@tanstack/angular-store@0.8.0(@angular/common@21.1.1(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))': + '@tanstack/angular-store@0.9.1(@angular/common@21.1.1(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2))(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))': dependencies: '@angular/common': 21.1.1(@angular/core@21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0))(rxjs@7.8.2) '@angular/core': 21.1.1(@angular/compiler@21.1.1)(rxjs@7.8.2)(zone.js@0.16.0) - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.9.1 tslib: 2.8.1 '@tanstack/devtools-client@0.0.5': @@ -15716,9 +15728,9 @@ snapshots: '@tanstack/pacer-lite@0.1.1': {} - '@tanstack/preact-store@0.10.1(preact@10.28.2)': + '@tanstack/preact-store@0.11.1(preact@10.28.2)': dependencies: - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.9.1 preact: 10.28.2 '@tanstack/publish-config@0.2.2': @@ -15776,6 +15788,13 @@ snapshots: react-dom: 19.2.4(react@19.2.4) use-sync-external-store: 1.6.0(react@19.2.4) + '@tanstack/react-store@0.9.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.9.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + '@tanstack/react-virtual@3.13.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/virtual-core': 3.13.18 @@ -15785,7 +15804,7 @@ snapshots: '@tanstack/router-core@1.157.16': dependencies: '@tanstack/history': 1.154.14 - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.8.1 cookie-es: 2.0.0 seroval: 1.4.2 seroval-plugins: 1.5.0(seroval@1.4.2) @@ -15852,18 +15871,22 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/solid-store@0.8.0(solid-js@1.9.11)': + '@tanstack/solid-store@0.8.1(solid-js@1.9.11)': dependencies: - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.8.1 solid-js: 1.9.11 '@tanstack/store@0.7.7': {} '@tanstack/store@0.8.0': {} - '@tanstack/svelte-store@0.9.0(svelte@5.48.5)': + '@tanstack/store@0.8.1': {} + + '@tanstack/store@0.9.1': {} + + '@tanstack/svelte-store@0.10.1(svelte@5.48.5)': dependencies: - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.9.1 svelte: 5.48.5 '@tanstack/typedoc-config@0.3.3(typescript@5.9.3)': @@ -15891,9 +15914,9 @@ snapshots: - supports-color - typescript - '@tanstack/vue-store@0.8.0(vue@3.5.27(typescript@5.9.3))': + '@tanstack/vue-store@0.9.1(vue@3.5.27(typescript@5.9.3))': dependencies: - '@tanstack/store': 0.8.0 + '@tanstack/store': 0.9.1 vue: 3.5.27(typescript@5.9.3) vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) From 3950949713df46cc1005acc6c4febdd424d1bbee Mon Sep 17 00:00:00 2001 From: Riccardo Perra Date: Wed, 25 Feb 2026 16:23:59 +0100 Subject: [PATCH 02/18] Update packages/table-core/src/core/table/constructTable.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- packages/table-core/src/core/table/constructTable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index daa80f34f7..927593da06 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -55,7 +55,7 @@ export function constructTable< table.baseStore = table.options.store ?? createStore(table.initialState) table.store = createStore(() => { - const state = table.baseStore.get() + const state = table.baseStore.state return { ...state, ...(table.options.state ?? {}), From 12b59301a62af697345dbab31c826c725aba39ab Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Wed, 25 Feb 2026 16:28:55 +0100 Subject: [PATCH 03/18] fix: lockfile --- pnpm-lock.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 56d6f8737f..1bb6bc3508 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2228,7 +2228,7 @@ importers: specifier: 0.9.6 version: 0.9.6(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) '@tanstack/react-table-devtools': - specifier: workspace:* + specifier: 9.0.0-alpha.11 version: link:../../../packages/react-table-devtools '@types/react': specifier: ^19.2.10 @@ -3642,7 +3642,7 @@ importers: version: 0.3.0(@types/react@19.2.10)(csstype@3.2.3)(preact@10.28.2)(react@19.2.4)(solid-js@1.9.11)(vue@3.5.27(typescript@5.9.3)) '@tanstack/solid-store': specifier: ^0.8.0 - version: 0.8.0(solid-js@1.9.11) + version: 0.8.1(solid-js@1.9.11) '@tanstack/table-core': specifier: workspace:* version: link:../table-core From 6eaa74102fbaa1581486db134093b25cd2284162 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 15:29:52 +0000 Subject: [PATCH 04/18] ci: apply automated fixes --- examples/react/row-selection/src/main.tsx | 371 +++++++++--------- packages/react-table-devtools/package.json | 12 +- .../src/ReactTableDevtools.tsx | 5 +- packages/table-devtools/package.json | 11 +- .../src/TableContextProvider.tsx | 18 +- .../src/components/FeaturesPanel.tsx | 131 +++---- .../src/components/RowsPanel.tsx | 124 +++--- packages/table-devtools/src/styles/tokens.ts | 3 +- .../table-devtools/src/styles/use-styles.ts | 5 +- 9 files changed, 359 insertions(+), 321 deletions(-) diff --git a/examples/react/row-selection/src/main.tsx b/examples/react/row-selection/src/main.tsx index d251e3f132..fbecd824f1 100644 --- a/examples/react/row-selection/src/main.tsx +++ b/examples/react/row-selection/src/main.tsx @@ -12,9 +12,7 @@ import { tableFeatures, useTable, } from '@tanstack/react-table' -import { - tableDevtoolsPlugin, -} from '@tanstack/react-table-devtools' +import { tableDevtoolsPlugin } from '@tanstack/react-table-devtools' import { TanStackDevtools } from '@tanstack/react-devtools' import { makeData } from './makeData' import type { HTMLProps } from 'react' @@ -126,191 +124,194 @@ function App() { > {(state) => (
-
- table.setGlobalFilter(e.target.value)} - className="p-2 font-lg shadow border border-block" - placeholder="Search all columns..." - /> -
-
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - ) - })} - - ))} - - - {table.getRowModel().rows.map((row) => { - return ( - state.rowSelection[row.id]} // only re-render row when row selection changes (could down move to cell render too) - > - {() => ( - - {row.getAllCells().map((cell) => { - return ( - - ) - })} - - )} - - ) - })} - - - - - - - -
- {header.isPlaceholder ? null : ( - <> - - {header.column.getCanFilter() ? ( -
- -
- ) : null} - - )} -
- -
- state.rowSelection}> - {() => ( - - )} - - - Page Rows ({table.getRowModel().rows.length}) -
-
-
- - - - - -
Page
- - {table.store.state.pagination.pageIndex + 1} of{' '} - {table.getPageCount()} - -
- - | Go to page: +
table.setGlobalFilter(e.target.value)} + className="p-2 font-lg shadow border border-block" + placeholder="Search all columns..." + /> +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + ) + })} + + ))} + + + {table.getRowModel().rows.map((row) => { + return ( + state.rowSelection[row.id]} // only re-render row when row selection changes (could down move to cell render too) + > + {() => ( + + {row.getAllCells().map((cell) => { + return ( + + ) + })} + + )} + + ) + })} + + + + + + + +
+ {header.isPlaceholder ? null : ( + <> + + {header.column.getCanFilter() ? ( +
+ +
+ ) : null} + + )} +
+ +
+ state.rowSelection}> + {() => ( + + )} + + + Page Rows ({table.getRowModel().rows.length}) +
+
+
+ + + + + +
Page
+ + {table.store.state.pagination.pageIndex + 1} of{' '} + {table.getPageCount()} + +
+ + | Go to page: + { + const page = e.target.value ? Number(e.target.value) - 1 : 0 + table.setPageIndex(page) + }} + className="border p-1 rounded w-16" + /> + + { - table.setPageSize(Number(e.target.value)) - }} - > - {[10, 20, 30, 40, 50].map((pageSize) => ( - - ))} - -
-
-
- ({ - numSelected: Object.keys(state.rowSelection).length, - })} - > - {({ numSelected }) => <>{numSelected} of } - - {table.getPreFilteredRowModel().rows.length} Total Rows Selected -
-
-
-
- -
-
- -
-
- -
-
- - state}> - {(state) =>
{JSON.stringify(state, null, 2)}
} -
-
+ > + {[10, 20, 30, 40, 50].map((pageSize) => ( + + ))} + +
+
+
+ ({ + numSelected: Object.keys(state.rowSelection).length, + })} + > + {({ numSelected }) => <>{numSelected} of } + + {table.getPreFilteredRowModel().rows.length} Total Rows Selected +
+
+
+
+ +
+
+ +
+
+ +
+
+ + state}> + {(state) =>
{JSON.stringify(state, null, 2)}
} +
+
)} diff --git a/packages/react-table-devtools/package.json b/packages/react-table-devtools/package.json index 2c4e8c15d6..1d18757cb1 100644 --- a/packages/react-table-devtools/package.json +++ b/packages/react-table-devtools/package.json @@ -14,7 +14,12 @@ "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, - "keywords": ["react", "tanstack", "table", "devtools"], + "keywords": [ + "react", + "tanstack", + "table", + "devtools" + ], "scripts": { "clean": "rimraf ./build && rimraf ./dist", "test:eslint": "eslint ./src", @@ -46,7 +51,10 @@ "engines": { "node": ">=16" }, - "files": ["dist", "src"], + "files": [ + "dist", + "src" + ], "dependencies": { "@tanstack/devtools-utils": "^0.3.0", "@tanstack/table-core": "workspace:*", diff --git a/packages/react-table-devtools/src/ReactTableDevtools.tsx b/packages/react-table-devtools/src/ReactTableDevtools.tsx index cb34e8553b..bc0a8c8781 100644 --- a/packages/react-table-devtools/src/ReactTableDevtools.tsx +++ b/packages/react-table-devtools/src/ReactTableDevtools.tsx @@ -1,6 +1,9 @@ import React from 'react' import { createReactPanel } from '@tanstack/devtools-utils/react' -import { TableDevtoolsCore, setTableDevtoolsTarget } from '@tanstack/table-devtools' +import { + TableDevtoolsCore, + setTableDevtoolsTarget, +} from '@tanstack/table-devtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' diff --git a/packages/table-devtools/package.json b/packages/table-devtools/package.json index 3c00ffdc47..e537c66e88 100644 --- a/packages/table-devtools/package.json +++ b/packages/table-devtools/package.json @@ -14,7 +14,11 @@ "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, - "keywords": ["tanstack", "table", "devtools"], + "keywords": [ + "tanstack", + "table", + "devtools" + ], "scripts": { "clean": "rimraf ./build && rimraf ./dist", "lint:fix": "eslint ./src --fix", @@ -47,7 +51,10 @@ "engines": { "node": ">=16" }, - "files": ["dist", "src"], + "files": [ + "dist", + "src" + ], "dependencies": { "@tanstack/devtools-ui": "^0.4.4", "@tanstack/devtools-utils": "^0.3.0", diff --git a/packages/table-devtools/src/TableContextProvider.tsx b/packages/table-devtools/src/TableContextProvider.tsx index 9d038b812b..9e2ee4a721 100644 --- a/packages/table-devtools/src/TableContextProvider.tsx +++ b/packages/table-devtools/src/TableContextProvider.tsx @@ -1,4 +1,10 @@ -import { createContext, createEffect, createSignal, onCleanup, useContext } from 'solid-js' +import { + createContext, + createEffect, + createSignal, + onCleanup, + useContext, +} from 'solid-js' import { getTableDevtoolsTarget, subscribeTableDevtoolsTarget, @@ -16,9 +22,9 @@ interface TableDevtoolsContextValue { setActiveTab: Setter } -const TableDevtoolsContext = createContext( - undefined, -) +const TableDevtoolsContext = createContext< + TableDevtoolsContextValue | undefined +>(undefined) export const TableContextProvider: ParentComponent = (props) => { const [table, setTable] = createSignal( @@ -51,7 +57,9 @@ export function useTableDevtoolsContext() { const context = useContext(TableDevtoolsContext) if (!context) { - throw new Error('useTableDevtoolsContext must be used within TableContextProvider') + throw new Error( + 'useTableDevtoolsContext must be used within TableContextProvider', + ) } return context diff --git a/packages/table-devtools/src/components/FeaturesPanel.tsx b/packages/table-devtools/src/components/FeaturesPanel.tsx index 67c5ffe48b..8c083cdc51 100644 --- a/packages/table-devtools/src/components/FeaturesPanel.tsx +++ b/packages/table-devtools/src/components/FeaturesPanel.tsx @@ -98,60 +98,60 @@ export function FeaturesPanel() {
Features
-
Core Features
- - {(name) => ( -
- - {tableFeatures.has(name) ? '✓' : '○'} - - {name} -
- )} -
-
- -
-
Stock Features
- - {(name) => ( -
- - {tableFeatures.has(name) ? '✓' : '○'} - - {name} -
- )} -
-
+
Core Features
+ + {(name) => ( +
+ + {tableFeatures.has(name) ? '✓' : '○'} + + {name} +
+ )} +
+
- {getAdditionalPlugins().length > 0 && (
-
- Additional Plugins -
- +
Stock Features
+ {(name) => (
- + + {tableFeatures.has(name) ? '✓' : '○'} + {name}
)}
- )} + + {getAdditionalPlugins().length > 0 && ( +
+
+ Additional Plugins +
+ + {(name) => ( +
+ + {name} +
+ )} +
+
+ )} } right={ @@ -160,33 +160,30 @@ export function FeaturesPanel() { Client Side Row Models and Fns
- {(rowModelName) => { - const fns = getRowModelFunctions(rowModelName) - return ( -
-
{rowModelName}
- - {(fnName) => ( -
{fnName}
- )} -
-
- ) - }} -
- {rowModelNames.length === 0 && ( -
No row models configured
- )} + {(rowModelName) => { + const fns = getRowModelFunctions(rowModelName) + return ( +
+
{rowModelName}
+ + {(fnName) => ( +
{fnName}
+ )} +
+
+ ) + }} + + {rowModelNames.length === 0 && ( +
No row models configured
+ )}
-
- Execution Order -
+
Execution Order
{(getter, index) => { const rowModelKey = getterToRowModelKey(getter) const isPresent = - rowModelKey !== null && - rowModelNames.includes(rowModelKey) + rowModelKey !== null && rowModelNames.includes(rowModelKey) return ( <> {index() > 0 && ' → '} diff --git a/packages/table-devtools/src/components/RowsPanel.tsx b/packages/table-devtools/src/components/RowsPanel.tsx index e482f9d52d..f840c6ed0b 100644 --- a/packages/table-devtools/src/components/RowsPanel.tsx +++ b/packages/table-devtools/src/components/RowsPanel.tsx @@ -5,7 +5,13 @@ import { useTableDevtoolsContext } from '../TableContextProvider' import { useStyles } from '../styles/use-styles' import { ResizableSplit } from './ResizableSplit' -import type { Cell, Column, Row, RowData, TableFeatures } from '@tanstack/table-core' +import type { + Cell, + Column, + Row, + RowData, + TableFeatures, +} from '@tanstack/table-core' type AnyRow = Row type AnyCell = Cell @@ -26,7 +32,8 @@ const ROW_MODEL_GETTERS = [ function stringifyValue(value: unknown): string { if (value == null) return '' if (typeof value === 'string') return value - if (typeof value === 'number' || typeof value === 'boolean') return String(value) + if (typeof value === 'number' || typeof value === 'boolean') + return String(value) if (value instanceof Date) return value.toISOString() try { @@ -44,9 +51,8 @@ export function RowsPanel() { ? useStore(tableInstance.store, (state) => state) : undefined - const [selectedRowModel, setSelectedRowModel] = createSignal< - (typeof ROW_MODEL_GETTERS)[number] - >('getRowModel') + const [selectedRowModel, setSelectedRowModel] = + createSignal<(typeof ROW_MODEL_GETTERS)[number]>('getRowModel') const getRawData = (): unknown => { tableState?.() @@ -88,9 +94,9 @@ export function RowsPanel() { const getAllRows = (): Array => { tableState?.() selectedRowModel() - const getter = tableInstance?.[ - selectedRowModel() - ] as (() => { rows: Array }) | undefined + const getter = tableInstance?.[selectedRowModel()] as + | (() => { rows: Array }) + | undefined return getter?.().rows ?? [] } @@ -124,7 +130,10 @@ export function RowsPanel() {
Raw Data {getRawDataTotalCount() > ROW_LIMIT && ( - (First {ROW_LIMIT} rows) + + {' '} + (First {ROW_LIMIT} rows) + )}
@@ -136,58 +145,61 @@ export function RowsPanel() { Rows ({getRows().length} {getRowsTotalCount() > ROW_LIMIT && ` of ${getRowsTotalCount()}`}) {getRowsTotalCount() > ROW_LIMIT && ( - — First {ROW_LIMIT} rows + + {' '} + — First {ROW_LIMIT} rows + )}
- - -
-
- - - - - - {(column) => ( - - )} - - - - - - {(row) => ( - - - - {(cell) => ( - - )} - - + + -
#{column.id}
{row.id} - {stringifyValue(cell.getValue())} -
-
+ +
+
+ + + + + + {(column) => ( + + )} + + + + + + {(row) => ( + + + + {(cell) => ( + + )} + + + )} + + +
#{column.id}
{row.id} + {stringifyValue(cell.getValue())} +
+
} /> diff --git a/packages/table-devtools/src/styles/tokens.ts b/packages/table-devtools/src/styles/tokens.ts index 66335681dd..051277ae27 100644 --- a/packages/table-devtools/src/styles/tokens.ts +++ b/packages/table-devtools/src/styles/tokens.ts @@ -55,8 +55,7 @@ export const tokens = { bold: 700, }, family: { - sans: - 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif', + sans: 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif', mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace', }, }, diff --git a/packages/table-devtools/src/styles/use-styles.ts b/packages/table-devtools/src/styles/use-styles.ts index f99496dda1..8360fa4a1f 100644 --- a/packages/table-devtools/src/styles/use-styles.ts +++ b/packages/table-devtools/src/styles/use-styles.ts @@ -43,7 +43,10 @@ const stylesFactory = (theme: 'light' | 'dark') => { } `, tabButtonActive: css` - background: ${t(colors.red[500] + alpha[20], colors.red[700] + alpha[20])}; + background: ${t( + colors.red[500] + alpha[20], + colors.red[700] + alpha[20], + )}; border-color: ${t(colors.red[500], colors.red[300])}; color: ${t(colors.red[700], colors.red[300])}; `, From 64773027530e07311501cdc818cf9cb5c5fb5c8a Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Wed, 25 Feb 2026 21:41:23 +0100 Subject: [PATCH 05/18] feat: add solid table devtools --- .../solid-table-devtools/eslint.config.js | 8 +++ packages/solid-table-devtools/package.json | 67 +++++++++++++++++++ .../src/SolidTableDevtools.tsx | 25 +++++++ packages/solid-table-devtools/src/index.ts | 17 +++++ packages/solid-table-devtools/src/plugin.tsx | 34 ++++++++++ .../solid-table-devtools/src/production.ts | 6 ++ .../solid-table-devtools/tsconfig.build.json | 13 ++++ packages/solid-table-devtools/tsconfig.json | 8 +++ packages/solid-table-devtools/vite.config.ts | 6 ++ 9 files changed, 184 insertions(+) create mode 100644 packages/solid-table-devtools/eslint.config.js create mode 100644 packages/solid-table-devtools/package.json create mode 100644 packages/solid-table-devtools/src/SolidTableDevtools.tsx create mode 100644 packages/solid-table-devtools/src/index.ts create mode 100644 packages/solid-table-devtools/src/plugin.tsx create mode 100644 packages/solid-table-devtools/src/production.ts create mode 100644 packages/solid-table-devtools/tsconfig.build.json create mode 100644 packages/solid-table-devtools/tsconfig.json create mode 100644 packages/solid-table-devtools/vite.config.ts diff --git a/packages/solid-table-devtools/eslint.config.js b/packages/solid-table-devtools/eslint.config.js new file mode 100644 index 0000000000..892f5314df --- /dev/null +++ b/packages/solid-table-devtools/eslint.config.js @@ -0,0 +1,8 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +/** @type {any} */ +const config = [...rootConfig] + +export default config diff --git a/packages/solid-table-devtools/package.json b/packages/solid-table-devtools/package.json new file mode 100644 index 0000000000..eea909e0ab --- /dev/null +++ b/packages/solid-table-devtools/package.json @@ -0,0 +1,67 @@ +{ + "name": "@tanstack/solid-table-devtools", + "version": "9.0.0-alpha.11", + "description": "Solid devtools for TanStack Table.", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/TanStack/table.git", + "directory": "packages/react-table-devtools" + }, + "homepage": "https://tanstack.com/table", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "solid", + "tanstack", + "table", + "devtools" + ], + "scripts": { + "clean": "rimraf ./build && rimraf ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "test:build": "publint --strict", + "build": "tsc -p tsconfig.build.json" + }, + "type": "module", + "types": "dist/index.d.ts", + "module": "dist/index.js", + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "./production": { + "import": { + "types": "./dist/production.d.ts", + "default": "./dist/production.js" + } + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=16" + }, + "files": [ + "dist", + "src" + ], + "dependencies": { + "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/table-core": "workspace:*", + "@tanstack/table-devtools": "workspace:*" + }, + "devDependencies": { + "solid-js": "^1.9.11", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/packages/solid-table-devtools/src/SolidTableDevtools.tsx b/packages/solid-table-devtools/src/SolidTableDevtools.tsx new file mode 100644 index 0000000000..2add8e7819 --- /dev/null +++ b/packages/solid-table-devtools/src/SolidTableDevtools.tsx @@ -0,0 +1,25 @@ +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid' +import { createSolidPanel } from '@tanstack/devtools-utils/solid' +import { + setTableDevtoolsTarget, + TableDevtoolsCore, +} from '@tanstack/table-devtools' + +import type { RowData, Table, TableFeatures } from '@tanstack/table-core' + +export interface TableDevtoolsSolidInit< + TFeatures extends TableFeatures = TableFeatures, + TData extends RowData = RowData, +> extends DevtoolsPanelProps { + table?: Table +} + +const [TableDevtoolsPanelBase, TableDevtoolsPanelNoOp] = + createSolidPanel(TableDevtoolsCore) + +function TableDevtoolsPanel(props: TableDevtoolsSolidInit) { + setTableDevtoolsTarget(props.table) + return +} + +export { TableDevtoolsPanel, TableDevtoolsPanelNoOp } diff --git a/packages/solid-table-devtools/src/index.ts b/packages/solid-table-devtools/src/index.ts new file mode 100644 index 0000000000..c34bc8c874 --- /dev/null +++ b/packages/solid-table-devtools/src/index.ts @@ -0,0 +1,17 @@ +'use client' + +import * as Devtools from './SolidTableDevtools' +import * as plugin from './plugin' + +export const TableDevtoolsPanel = + process.env.NODE_ENV !== 'development' + ? Devtools.TableDevtoolsPanelNoOp + : Devtools.TableDevtoolsPanel + +export const tableDevtoolsPlugin = + process.env.NODE_ENV !== 'development' + ? plugin.tableDevtoolsNoOpPlugin + : plugin.tableDevtoolsPlugin + +export type { TableDevtoolsSolidInit } from './SolidTableDevtools' +export type { TableDevtoolsPluginOptions } from './plugin' diff --git a/packages/solid-table-devtools/src/plugin.tsx b/packages/solid-table-devtools/src/plugin.tsx new file mode 100644 index 0000000000..dfc00d2760 --- /dev/null +++ b/packages/solid-table-devtools/src/plugin.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import { TableDevtoolsPanel } from './SolidTableDevtools' +import type { RowData, Table, TableFeatures } from '@tanstack/table-core' + +export interface TableDevtoolsPluginOptions< + TFeatures extends TableFeatures = TableFeatures, + TData extends RowData = RowData, +> { + table: Table +} + +function tableDevtoolsPlugin< + TFeatures extends TableFeatures = TableFeatures, + TData extends RowData = RowData, +>(options: TableDevtoolsPluginOptions) { + return { + name: 'TanStack Table', + render: (_el: HTMLElement, theme: 'light' | 'dark') => ( + + ), + } +} + +function tableDevtoolsNoOpPlugin< + TFeatures extends TableFeatures = TableFeatures, + TData extends RowData = RowData, +>(_options: TableDevtoolsPluginOptions) { + return { + name: 'TanStack Table', + render: (_el: HTMLElement, _theme: 'light' | 'dark') => <>, + } +} + +export { tableDevtoolsPlugin, tableDevtoolsNoOpPlugin } diff --git a/packages/solid-table-devtools/src/production.ts b/packages/solid-table-devtools/src/production.ts new file mode 100644 index 0000000000..b197295f30 --- /dev/null +++ b/packages/solid-table-devtools/src/production.ts @@ -0,0 +1,6 @@ +'use client' + +export { TableDevtoolsPanel } from './SolidTableDevtools' +export type { TableDevtoolsSolidInit } from './SolidTableDevtools' +export { tableDevtoolsPlugin } from './plugin' +export type { TableDevtoolsPluginOptions } from './plugin' diff --git a/packages/solid-table-devtools/tsconfig.build.json b/packages/solid-table-devtools/tsconfig.build.json new file mode 100644 index 0000000000..93755fa253 --- /dev/null +++ b/packages/solid-table-devtools/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js", + "rootDir": "src", + "outDir": "dist", + "noEmit": false, + "declaration": true, + "sourceMap": true + }, + "include": ["src"] +} diff --git a/packages/solid-table-devtools/tsconfig.json b/packages/solid-table-devtools/tsconfig.json new file mode 100644 index 0000000000..966bd728f5 --- /dev/null +++ b/packages/solid-table-devtools/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + }, + "include": ["src", "eslint.config.js", "vite.config.ts", "tests"] +} diff --git a/packages/solid-table-devtools/vite.config.ts b/packages/solid-table-devtools/vite.config.ts new file mode 100644 index 0000000000..a872ffe359 --- /dev/null +++ b/packages/solid-table-devtools/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vitest/config' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [solid()], +}) From bbb67c1bf20704a549fef6436b8c73e26078d9cd Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Wed, 25 Feb 2026 21:41:48 +0100 Subject: [PATCH 06/18] feat: add table devtools options panel --- packages/table-devtools/package.json | 2 +- .../src/TableContextProvider.tsx | 7 +-- .../src/components/OptionsPanel.tsx | 40 +++++++++++++ .../table-devtools/src/components/Shell.tsx | 5 ++ pnpm-lock.yaml | 56 ++++++++++++++++--- 5 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 packages/table-devtools/src/components/OptionsPanel.tsx diff --git a/packages/table-devtools/package.json b/packages/table-devtools/package.json index e537c66e88..764f5c2e59 100644 --- a/packages/table-devtools/package.json +++ b/packages/table-devtools/package.json @@ -58,7 +58,7 @@ "dependencies": { "@tanstack/devtools-ui": "^0.4.4", "@tanstack/devtools-utils": "^0.3.0", - "@tanstack/solid-store": "^0.8.0", + "@tanstack/solid-store": "^0.9.1", "clsx": "^2.1.1", "goober": "^2.1.18", "solid-js": "^1.9.11" diff --git a/packages/table-devtools/src/TableContextProvider.tsx b/packages/table-devtools/src/TableContextProvider.tsx index 9e2ee4a721..3bde692456 100644 --- a/packages/table-devtools/src/TableContextProvider.tsx +++ b/packages/table-devtools/src/TableContextProvider.tsx @@ -9,12 +9,11 @@ import { getTableDevtoolsTarget, subscribeTableDevtoolsTarget, } from './tableTarget' - import type { Accessor, ParentComponent, Setter } from 'solid-js' -import type { RowData, Table, TableFeatures } from '@tanstack/table-core' +import type { RowData, Table, stockFeatures } from '@tanstack/table-core' -export type TableDevtoolsTabId = 'features' | 'state' | 'rows' -type AnyTable = Table +export type TableDevtoolsTabId = 'features' | 'state' | 'options' | 'rows' +type AnyTable = Table interface TableDevtoolsContextValue { table: Accessor diff --git a/packages/table-devtools/src/components/OptionsPanel.tsx b/packages/table-devtools/src/components/OptionsPanel.tsx new file mode 100644 index 0000000000..011be836e8 --- /dev/null +++ b/packages/table-devtools/src/components/OptionsPanel.tsx @@ -0,0 +1,40 @@ +import { JsonTree } from '@tanstack/devtools-ui' +import { useStore } from '@tanstack/solid-store' +import { useTableDevtoolsContext } from '../TableContextProvider' +import { useStyles } from '../styles/use-styles' +import { ResizableSplit } from './ResizableSplit' + +export function OptionsPanel() { + const styles = useStyles() + const { table } = useTableDevtoolsContext() + + const tableInstance = table() + const tableState = tableInstance + ? useStore( + tableInstance.baseOptionsStore, + ({ state, data, _features, _rowModels, ...options }) => options, + ) + : undefined + + const getState = (): unknown => { + tableState?.() + if (!tableInstance) { + return undefined + } + return tableState?.() + } + + return ( +
+ +
Options
+ + + } + right={<>} + /> +
+ ) +} diff --git a/packages/table-devtools/src/components/Shell.tsx b/packages/table-devtools/src/components/Shell.tsx index 0883357e8d..76ad3a4e62 100644 --- a/packages/table-devtools/src/components/Shell.tsx +++ b/packages/table-devtools/src/components/Shell.tsx @@ -5,10 +5,12 @@ import { useStyles } from '../styles/use-styles' import { FeaturesPanel } from './FeaturesPanel' import { RowsPanel } from './RowsPanel' import { StatePanel } from './StatePanel' +import { OptionsPanel } from './OptionsPanel' const tabs = [ { id: 'features', label: 'Features' }, { id: 'state', label: 'State' }, + { id: 'options', label: 'Options' }, { id: 'rows', label: 'Rows' }, ] as const @@ -52,6 +54,9 @@ export function Shell() { + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1bb6bc3508..f07a48dde3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2775,9 +2775,15 @@ importers: examples/solid/row-selection: dependencies: + '@tanstack/solid-devtools': + specifier: ^0.7.26 + version: 0.7.26(csstype@3.2.3)(solid-js@1.9.11) '@tanstack/solid-table': specifier: ^9.0.0-alpha.10 version: link:../../../packages/solid-table + '@tanstack/solid-table-devtools': + specifier: 9.0.0-alpha.11 + version: link:../../../packages/solid-table-devtools solid-js: specifier: ^1.9.11 version: 1.9.11 @@ -3588,8 +3594,8 @@ importers: packages/solid-table: dependencies: '@tanstack/solid-store': - specifier: ^0.8.0 - version: 0.8.1(solid-js@1.9.11) + specifier: ^0.9.1 + version: 0.9.1(solid-js@1.9.11) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -3601,6 +3607,25 @@ importers: specifier: ^2.11.10 version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2)) + packages/solid-table-devtools: + dependencies: + '@tanstack/devtools-utils': + specifier: ^0.3.0 + version: 0.3.0(@types/react@19.2.10)(csstype@3.2.3)(preact@10.28.2)(react@19.2.4)(solid-js@1.9.11)(vue@3.5.27(typescript@5.9.3)) + '@tanstack/table-core': + specifier: workspace:* + version: link:../table-core + '@tanstack/table-devtools': + specifier: workspace:* + version: link:../table-devtools + devDependencies: + solid-js: + specifier: ^1.9.11 + version: 1.9.11 + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2)) + packages/svelte-table: dependencies: '@tanstack/svelte-store': @@ -3641,8 +3666,8 @@ importers: specifier: ^0.3.0 version: 0.3.0(@types/react@19.2.10)(csstype@3.2.3)(preact@10.28.2)(react@19.2.4)(solid-js@1.9.11)(vue@3.5.27(typescript@5.9.3)) '@tanstack/solid-store': - specifier: ^0.8.0 - version: 0.8.1(solid-js@1.9.11) + specifier: ^0.9.1 + version: 0.9.1(solid-js@1.9.11) '@tanstack/table-core': specifier: workspace:* version: link:../table-core @@ -7258,8 +7283,14 @@ packages: resolution: {integrity: sha512-Lvq5VnH9Rtqci0urHENMMlyswN5fySvIANclS7cUq2xOr5Cc9QfPpwctZ3Bi1X+MibKIcXplTAixIYDFyYquQg==} engines: {node: '>=12'} - '@tanstack/solid-store@0.8.1': - resolution: {integrity: sha512-1p4TTJGIZJ2J7130aTo7oWfHVRSCd9DxLP3HzcDMnzn56pz8krlyBEzsE+z/sHGXP0EC/JjT02fgj2L9+fmf8Q==} + '@tanstack/solid-devtools@0.7.26': + resolution: {integrity: sha512-HagP7imKP6I+GVaHZp3GvwKUZ4qTHkMmZVOK6+uFrlDDJNtKBEblMW1jyGsh0NKrbajTW2KNT0AlylRu5vsR/A==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/solid-store@0.9.1': + resolution: {integrity: sha512-gx7ToM+Yrkui36NIj0HjAufzv1Dg8usjtVFy5H3Ll52Xjuz+eliIJL+ihAr4LRuWh3nDPBR+nCLW0ShFrbE5yw==} peerDependencies: solid-js: ^1.6.0 @@ -15871,9 +15902,18 @@ snapshots: - vite-plugin-solid - webpack - '@tanstack/solid-store@0.8.1(solid-js@1.9.11)': + '@tanstack/solid-devtools@0.7.26(csstype@3.2.3)(solid-js@1.9.11)': dependencies: - '@tanstack/store': 0.8.1 + '@tanstack/devtools': 0.10.7(csstype@3.2.3)(solid-js@1.9.11) + solid-js: 1.9.11 + transitivePeerDependencies: + - bufferutil + - csstype + - utf-8-validate + + '@tanstack/solid-store@0.9.1(solid-js@1.9.11)': + dependencies: + '@tanstack/store': 0.9.1 solid-js: 1.9.11 '@tanstack/store@0.7.7': {} From 67d022a33576e37d03ad96030c0a315ba7218dd2 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Wed, 25 Feb 2026 22:26:06 +0100 Subject: [PATCH 07/18] feat: move reactivity feature to core --- examples/solid/row-selection/package.json | 2 + examples/solid/row-selection/src/App.tsx | 51 +++-- packages/angular-table/src/index.ts | 1 - packages/angular-table/src/injectTable.ts | 21 +- .../angular-table/tests/injectTable.test.ts | 2 +- .../tests/reactivityUtils.test.ts | 210 ------------------ packages/solid-table/package.json | 2 +- packages/solid-table/src/createTable.ts | 106 +++++++-- packages/solid-table/src/createTableHelper.ts | 9 +- .../src/core/table/constructTable.ts | 12 +- .../src/core/table/coreTablesFeature.types.ts | 6 +- .../src/core/table/coreTablesFeature.utils.ts | 6 +- .../tableReactivityFeature.ts} | 102 +++++---- .../tableReactivityFeature.utils.ts} | 71 +++--- packages/table-core/src/index.ts | 4 + 15 files changed, 267 insertions(+), 338 deletions(-) delete mode 100644 packages/angular-table/tests/reactivityUtils.test.ts rename packages/{angular-table/src/angularReactivityFeature.ts => table-core/src/features/table-reactivity/tableReactivityFeature.ts} (70%) rename packages/{angular-table/src/reactivityUtils.ts => table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts} (83%) diff --git a/examples/solid/row-selection/package.json b/examples/solid/row-selection/package.json index 82cbf8ce2b..8fdf7ab281 100644 --- a/examples/solid/row-selection/package.json +++ b/examples/solid/row-selection/package.json @@ -18,6 +18,8 @@ }, "dependencies": { "@tanstack/solid-table": "^9.0.0-alpha.10", + "@tanstack/solid-devtools": "^0.7.26", + "@tanstack/solid-table-devtools": "9.0.0-alpha.11", "solid-js": "^1.9.11" } } diff --git a/examples/solid/row-selection/src/App.tsx b/examples/solid/row-selection/src/App.tsx index 57991b86f0..7e22049531 100644 --- a/examples/solid/row-selection/src/App.tsx +++ b/examples/solid/row-selection/src/App.tsx @@ -1,3 +1,9 @@ +import type { + Column, + ColumnDef, + SolidTable, + Table, +} from '@tanstack/solid-table' import { columnFilteringFeature, createFilteredRowModel, @@ -11,15 +17,11 @@ import { tableFeatures, } from '@tanstack/solid-table' import { For, Show, createEffect, createSignal } from 'solid-js' -import { makeData } from './makeData' -import type { - Column, - ColumnDef, - SolidTable, - Table, -} from '@tanstack/solid-table' import type { Person } from './makeData' +import { makeData } from './makeData' import './index.css' +import { TanStackDevtools } from '@tanstack/solid-devtools' +import { tableDevtoolsPlugin } from '@tanstack/solid-table-devtools' export const _features = tableFeatures({ rowPaginationFeature, @@ -51,16 +53,18 @@ function App() { ) }, - cell: ({ row }) => ( -
- -
- ), + cell: ({ row }) => { + return ( +
+ +
+ ) + }, }, { header: 'Name', @@ -113,6 +117,8 @@ function App() { }, ] + const [enableRowSelection, setEnableRowSelection] = createSignal(true) + table = createTable({ _features, _rowModels: { @@ -124,11 +130,14 @@ function App() { }, columns, getRowId: (row) => row.id, - enableRowSelection: true, // enable row selection for all rows - // enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row + get enableRowSelection() { + return enableRowSelection() + }, debugTable: true, }) + window.setEnable = setEnableRowSelection + return ( // ({ @@ -140,6 +149,8 @@ function App() { // > // {(state) => (
+ +
({ globalFilter: state.globalFilter })} @@ -333,8 +344,6 @@ function App() {
- // )} - //
) } diff --git a/packages/angular-table/src/index.ts b/packages/angular-table/src/index.ts index e51f5d5043..6147ee1b65 100644 --- a/packages/angular-table/src/index.ts +++ b/packages/angular-table/src/index.ts @@ -3,7 +3,6 @@ import { FlexRenderDirective } from './flexRender' export * from '@tanstack/table-core' -export * from './angularReactivityFeature' export * from './flexRender' export * from './injectTable' export * from './flex-render/flexRenderComponent' diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index c1cbc5d8fd..c50bac00c0 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -3,12 +3,16 @@ import { assertInInjectionContext, computed, inject, + isSignal, + signal, untracked, } from '@angular/core' -import { constructTable } from '@tanstack/table-core' +import { + constructReactivityFeature, + constructTable, +} from '@tanstack/table-core' import { injectStore } from '@tanstack/angular-store' import { lazyInit } from './lazySignalInitializer' -import { angularReactivityFeature } from './angularReactivityFeature' import type { RowData, Table, @@ -104,6 +108,16 @@ export function injectTable< assertInInjectionContext(injectTable) const injector = inject(Injector) + const angularReactivityFeature = constructReactivityFeature({ + createSignal: (value) => { + return signal(value) as any + }, + createMemo: (fn) => { + return computed(() => fn()) + }, + isSignal: (value) => isSignal(value), + }) + return lazyInit(() => { const resolvedOptions: TableOptions = { ...options(), @@ -142,7 +156,8 @@ export function injectTable< const tableSignalNotifier = computed( () => { tableState() - table.setOptions(updatedOptions()) + const newOptions = updatedOptions() + untracked(() => table.setOptions(newOptions)) untracked(() => table.baseStore.setState((prev) => ({ ...prev }))) return table }, diff --git a/packages/angular-table/tests/injectTable.test.ts b/packages/angular-table/tests/injectTable.test.ts index 1f74844c66..e2700dcb8a 100644 --- a/packages/angular-table/tests/injectTable.test.ts +++ b/packages/angular-table/tests/injectTable.test.ts @@ -75,7 +75,7 @@ describe('injectTable', () => { }) test('supports "Object.keys"', () => { - const keys = Object.keys(table.get()).concat('state') + const keys = Object.keys(table.value()).concat('state') expect(Object.keys(table)).toEqual(keys) }) diff --git a/packages/angular-table/tests/reactivityUtils.test.ts b/packages/angular-table/tests/reactivityUtils.test.ts deleted file mode 100644 index 5aff11bf23..0000000000 --- a/packages/angular-table/tests/reactivityUtils.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { describe, expect, test, vi } from 'vitest' -import { effect, isSignal, signal } from '@angular/core' -import { TestBed } from '@angular/core/testing' -import { defineLazyComputedProperty, toComputed } from '../src/reactivityUtils' - -describe('toComputed', () => { - describe('args = 0', () => { - test('creates a computed', () => { - const notifier = signal(1) - - const result = toComputed( - notifier, - () => { - return notifier() * 2 - }, - 'double', - ) - - expect(result.name).toEqual('double') - expect(isSignal(result)).toEqual(true) - - TestBed.runInInjectionContext(() => { - const mockFn = vi.fn() - - effect(() => { - mockFn(result()) - }) - - TestBed.tick() - expect(mockFn).toHaveBeenLastCalledWith(2) - - notifier.set(3) - TestBed.tick() - expect(mockFn).toHaveBeenLastCalledWith(6) - - notifier.set(2) - TestBed.tick() - expect(mockFn).toHaveBeenLastCalledWith(4) - - expect(mockFn.mock.calls.length).toEqual(3) - }) - }) - }) - - describe('args >= 1', () => { - test('creates a fn an explicit first argument and allows other args', () => { - const notifier = signal(1) - - const fn1 = toComputed( - notifier, - (arg0: number, arg1: string, arg3?: number) => { - return { arg0, arg1, arg3 } - }, - '3args', - ) - expect(fn1.length).toEqual(0) - - // currently full rest parameters is not supported - const fn2 = toComputed( - notifier, - function myFn(...args: Array) { - return args - }, - '3args', - ) - expect(fn2.length).toEqual(0) - }) - - test('reuse created computed when args are the same', () => { - const notifier = signal(1) - - const invokeMock = vi.fn() - - const sum = toComputed( - notifier, - (arg0: number, arg1?: string) => { - invokeMock(arg0) - return notifier() + arg0 - }, - 'sum', - ) - - sum(1) - sum(3) - sum(2) - sum(1) - sum(1) - sum(2) - sum(3) - - expect(invokeMock).toHaveBeenCalledTimes(3) - expect(invokeMock).toHaveBeenNthCalledWith(1, 1) - expect(invokeMock).toHaveBeenNthCalledWith(2, 3) - expect(invokeMock).toHaveBeenNthCalledWith(3, 2) - }) - - test('cached computed are reactive', () => { - const invokeMock = vi.fn() - const notifier = signal(1) - - const sum = toComputed( - notifier, - (arg0: number) => { - invokeMock(arg0) - return notifier() + arg0 - }, - 'sum', - ) - - TestBed.runInInjectionContext(() => { - const mockSumBy3Fn = vi.fn() - const mockSumBy2Fn = vi.fn() - - effect(() => { - mockSumBy3Fn(sum(3)) - }) - effect(() => { - mockSumBy2Fn(sum(2)) - }) - - TestBed.flushEffects() - expect(mockSumBy3Fn).toHaveBeenLastCalledWith(4) - expect(mockSumBy2Fn).toHaveBeenLastCalledWith(3) - - notifier.set(2) - TestBed.flushEffects() - expect(mockSumBy3Fn).toHaveBeenLastCalledWith(5) - expect(mockSumBy2Fn).toHaveBeenLastCalledWith(4) - - expect(mockSumBy3Fn.mock.calls.length).toEqual(2) - expect(mockSumBy2Fn.mock.calls.length).toEqual(2) - }) - - for (let i = 0; i < 4; i++) { - sum(3) - sum(2) - } - // invoked every time notifier change - expect(invokeMock).toHaveBeenCalledTimes(4) - }) - }) - - describe('args 0~1', () => { - test('creates a fn an explicit first argument and allows other args', () => { - const notifier = signal(1) - const captor = vi.fn<(arg0?: number) => void>() - const captor2 = vi.fn<(arg0?: number) => void>() - - const fn1 = toComputed( - notifier, - (arg0: number | undefined) => { - if (arg0 === undefined) { - return 5 * notifier() - } - return arg0 * notifier() - }, - 'optionalArgs', - ) - - expect(isSignal(fn1)).toEqual(false) - - TestBed.runInInjectionContext(() => { - effect(() => { - captor(fn1(0)) - }) - effect(() => { - captor2(fn1(1)) - }) - }) - - TestBed.tick() - notifier.set(2) - TestBed.tick() - notifier.set(3) - expect(captor.mock.calls).toHaveLength(1) - expect(captor2.mock.calls).toHaveLength(2) - expect(captor2).toHaveBeenNthCalledWith(1, 1) - expect(captor2).toHaveBeenNthCalledWith(2, 2) - }) - }) -}) - -describe('defineLazyComputedProperty', () => { - test('define a computed property and cache the result after first access', () => { - const notifier = signal(1) - const originalObject = {} as any - const mockValueFn = vi.fn(() => 2) - - defineLazyComputedProperty(notifier, { - originalObject, - property: 'computedProp', - valueFn: mockValueFn, - }) - - let propDescriptor = Object.getOwnPropertyDescriptor( - originalObject, - 'computedProp', - ) - expect(propDescriptor && !!propDescriptor.get).toEqual(true) - - originalObject.computedProp - - propDescriptor = Object.getOwnPropertyDescriptor( - originalObject, - 'computedProp', - ) - expect(propDescriptor!.get).not.toBeDefined() - expect(isSignal(propDescriptor!.value)) - }) -}) diff --git a/packages/solid-table/package.json b/packages/solid-table/package.json index 9638c02201..8162065bfa 100644 --- a/packages/solid-table/package.json +++ b/packages/solid-table/package.json @@ -52,7 +52,7 @@ "build": "tsc -p tsconfig.build.json" }, "dependencies": { - "@tanstack/solid-store": "^0.8.0", + "@tanstack/solid-store": "^0.9.1", "@tanstack/table-core": "workspace:*" }, "devDependencies": { diff --git a/packages/solid-table/src/createTable.ts b/packages/solid-table/src/createTable.ts index 0e91d32dab..13f68366be 100644 --- a/packages/solid-table/src/createTable.ts +++ b/packages/solid-table/src/createTable.ts @@ -1,6 +1,17 @@ -import { constructTable } from '@tanstack/table-core' +import { + constructReactivityFeature, + constructTable, +} from '@tanstack/table-core' import { useStore } from '@tanstack/solid-store' -import { createComputed, createSignal } from 'solid-js' +import { + createComputed, + createMemo, + createSignal, + getOwner, + mergeProps, + runWithOwner, +} from 'solid-js' +import type { Accessor, JSX } from 'solid-js' import type { NoInfer, RowData, @@ -9,7 +20,6 @@ import type { TableOptions, TableState, } from '@tanstack/table-core' -import type { Accessor, JSX } from 'solid-js' export type SolidTable< TFeatures extends TableFeatures, @@ -54,21 +64,75 @@ export function createTable< selector: (state: TableState) => TSelected = () => ({}) as TSelected, ): SolidTable { - const table = constructTable(tableOptions) as SolidTable< + const owner = getOwner() + + const solidReactivityFeature = constructReactivityFeature({ + createSignal: (value) => { + const signal = createSignal(value) + function interoperableSignal() { + return signal[0]() + } + return Object.assign(interoperableSignal, { + set: (value: any) => signal[1](() => value), + }) + }, + createMemo: (fn) => { + if (owner) { + return runWithOwner(owner, () => createMemo(fn))! + } + return createMemo(fn) + }, + isSignal: (value) => typeof value === 'function', + }) + + const mergedOptions = mergeProps(tableOptions, { + _features: mergeProps(tableOptions._features, { + solidReactivityFeature, + }), + }) as any + + const [renderVersion, setRenderVersion] = createSignal(0) + + const resolvedOptions = mergeProps( + { + mergeOptions: ( + defaultOptions: TableOptions, + options: TableOptions, + ) => { + return mergeProps(defaultOptions, options) + }, + }, + mergedOptions, + ) as TableOptions + + const table = constructTable(resolvedOptions) as SolidTable< TFeatures, TData, TSelected > + // @ts-ignore + table.setTableNotifier(() => { + renderVersion() + return table + }) + /** * Temp force reactivity to all state changes on every table.get* method */ const allState = useStore(table.store, (state) => state) - const [renderVersion, setRenderVersion] = createSignal(0) + const allOptions = useStore(table.baseOptionsStore, (options) => options) + + createComputed(() => { + table.setOptions((prev) => { + return mergeProps(prev, mergedOptions) as TableOptions + }) + }) createComputed(() => { // Access storeState to create reactive dependency allState() + allOptions() // Increment version to invalidate cached get* methods setRenderVersion((v) => v + 1) // Update options when store changes @@ -77,17 +141,27 @@ export function createTable< // }) }) - // Wrap all "get*" methods to make them reactive - Object.keys(table).forEach((key) => { - const value = (table as any)[key] - if (typeof value === 'function' && key.startsWith('get')) { - const originalMethod = value.bind(table) - ;(table as any)[key] = (...args: Array) => { - renderVersion() - return originalMethod(...args) - } - } - }) + // Object.assign(table, { + // get options() { + // allOptions() + // return table.baseOptionsStore.get() + // }, + // }) + // + // Object.defineProperty(table.store, 'get', { + // value: () => { + // allState() + // allOptions() + // return table.store['atom'].get() + // }, + // }) + // Object.defineProperty(table.store, 'state', { + // get() { + // allState() + // allOptions() + // return this['atom'].get() + // }, + // }) table.Subscribe = function Subscribe(props: { selector: (state: TableState) => TSelected diff --git a/packages/solid-table/src/createTableHelper.ts b/packages/solid-table/src/createTableHelper.ts index dfbe95ea1d..768899cf12 100644 --- a/packages/solid-table/src/createTableHelper.ts +++ b/packages/solid-table/src/createTableHelper.ts @@ -13,7 +13,7 @@ import type { export type TableHelper< TFeatures extends TableFeatures, TData extends RowData = any, -> = Omit, 'tableCreator'> & { +> = Omit, 'tableCreator'> & { createTable: ( tableOptions: Omit< TableOptions, @@ -27,9 +27,12 @@ export function createTableHelper< TFeatures extends TableFeatures, TData extends RowData = any, >( - tableHelperOptions: TableHelperOptions, + tableHelperOptions: TableHelperOptions, ): TableHelper { - const tableHelper = constructTableHelper(createTable, tableHelperOptions) + const tableHelper = constructTableHelper( + createTable as any, + tableHelperOptions, + ) return { ...tableHelper, createTable: ( diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index 927593da06..0b94cc6f85 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -42,10 +42,18 @@ export function constructTable< return Object.assign(obj, feature.getDefaultTableOptions?.(table)) }, {}) as TableOptions - table.options = { + table.baseOptionsStore = createStore({ ...defaultOptions, ...tableOptions, - } + }) + + Object.defineProperty(table, 'options', { + enumerable: true, + configurable: true, + get() { + return table.baseOptionsStore.state + }, + }) table.initialState = getInitialTableState( table._features, diff --git a/packages/table-core/src/core/table/coreTablesFeature.types.ts b/packages/table-core/src/core/table/coreTablesFeature.types.ts index 53e88695f9..f80e21c33b 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.types.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.types.ts @@ -94,6 +94,10 @@ export interface Table_CoreProperties< * The base store for the table. This can be used to write to the table state. */ baseStore: Store> + /** + * The base store for the table. This can be used to write to the table state. + */ + baseOptionsStore: Store> /** * This is the resolved initial state of the table. */ @@ -101,7 +105,7 @@ export interface Table_CoreProperties< /** * A read-only reference to the table's current options. */ - options: TableOptions + readonly options: TableOptions /** * Where the table state is stored. */ diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 85c2cd7869..436a5f1e88 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -35,6 +35,8 @@ export function table_setOptions< table: Table_Internal, updater: Updater>, ): void { - const newOptions = functionalUpdate(updater, table.options) - table.options = table_mergeOptions(table, newOptions) + table.baseOptionsStore.setState((options) => { + const newOptions = functionalUpdate(updater, options) + return table_mergeOptions(table, newOptions) + }) } diff --git a/packages/angular-table/src/angularReactivityFeature.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts similarity index 70% rename from packages/angular-table/src/angularReactivityFeature.ts rename to packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts index 76b3433310..15a3360a23 100644 --- a/packages/angular-table/src/angularReactivityFeature.ts +++ b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts @@ -1,6 +1,5 @@ -import { computed, signal } from '@angular/core' -import { setReactivePropertiesOnObject } from './reactivityUtils' -import type { Signal } from '@angular/core' +import { setReactivePropertiesOnObject } from './tableReactivityFeature.utils' +import type { Accessor } from './tableReactivityFeature.utils' import type { RowData, Table, @@ -8,18 +7,6 @@ import type { TableFeatures, } from '@tanstack/table-core' -declare module '@tanstack/table-core' { - interface TableOptions_Plugins< - TFeatures extends TableFeatures, - TData extends RowData, - > extends TableOptions_AngularReactivity {} - - interface Table_Plugins< - TFeatures extends TableFeatures, - TData extends RowData, - > extends Table_AngularReactivity {} -} - /** * Predicate used to skip/ignore a property name when applying Angular reactivity. * @@ -68,7 +55,7 @@ export interface AngularReactivityFlags { * * Available on `createTable` options via module augmentation in this file. */ -interface TableOptions_AngularReactivity { +interface TableOptions_Reactivity { /** * Enables/disables and configures Angular reactivity on table-related prototypes. * @@ -82,31 +69,31 @@ interface TableOptions_AngularReactivity { * * Added to the table instance via module augmentation. */ -interface Table_AngularReactivity< +interface Table_Reactivity< TFeatures extends TableFeatures, TData extends RowData, > { /** * Returns a table signal that updates whenever the table state or options changes. */ - get: Signal> + value: Accessor> /** * Sets the reactive notifier that powers {@link get}. * * @internal Used by the Angular table adapter to connect its notifier to the core table. */ - setTableNotifier: (signal: Signal>) => void + setTableNotifier: (signal: Accessor>) => void } /** * Type map describing what this feature adds to TanStack Table constructors. */ -interface AngularReactivityFeatureConstructors< +interface TableReactivityFeatureConstructors< TFeatures extends TableFeatures, TData extends RowData, > { - TableOptions: TableOptions_AngularReactivity - Table: Table_AngularReactivity + TableOptions: TableOptions_Reactivity + Table: Table_Reactivity } /** @@ -127,10 +114,25 @@ const getUserSkipPropertyFn = ( return value ?? defaultPropertyFn } -function constructAngularReactivityFeature< +export type InteroperableWritableSignal = { + (): T + set: (value: unknown) => void +} + +export interface ReactivityFeatureFactoryOptions { + createSignal: (value: T) => InteroperableWritableSignal + createMemo: (accessor: Accessor) => Accessor + isSignal: (v: unknown) => boolean +} + +export function constructReactivityFeature< TFeatures extends TableFeatures, TData extends RowData, ->(): TableFeature> { +>( + factory: ReactivityFeatureFactoryOptions, +): TableFeature> { + const { createSignal, createMemo } = factory + return { getDefaultTableOptions(table) { return { @@ -143,77 +145,97 @@ function constructAngularReactivityFeature< } }, constructTableAPIs: (table) => { - const rootNotifier = signal | null>(null) - table.setTableNotifier = (notifier) => rootNotifier.set(notifier) - table.get = computed(() => rootNotifier()!(), { equal: () => false }) - setReactivePropertiesOnObject(table.get, table, { + const rootNotifier = createSignal + > | null>(null) + + table.setTableNotifier = (notifier) => { + rootNotifier.set(notifier) + } + + table.value = () => { + const notifier = rootNotifier() + void notifier?.() + return table as any + } + + setReactivePropertiesOnObject(table.value, table, { overridePrototype: false, skipProperty: skipBaseProperties, + factory, }) }, assignCellPrototype: (prototype, table) => { + // @ts-expect-error Internal if (table.options.reactivity?.cell === false) { return } - setReactivePropertiesOnObject(table.get, prototype, { + // @ts-expect-error Internal + setReactivePropertiesOnObject(table.value, prototype, { skipProperty: getUserSkipPropertyFn( + // @ts-expect-error Internal table.options.reactivity?.cell, skipBaseProperties, ), overridePrototype: true, + factory, }) }, assignColumnPrototype: (prototype, table) => { + // @ts-expect-error Internal if (table.options.reactivity?.column === false) { return } - setReactivePropertiesOnObject(table.get, prototype, { + // @ts-expect-error Internal + setReactivePropertiesOnObject(table.value, prototype, { skipProperty: getUserSkipPropertyFn( + // @ts-expect-error Internal table.options.reactivity?.cell, skipBaseProperties, ), overridePrototype: true, + factory, }) }, assignHeaderPrototype: (prototype, table) => { + // @ts-expect-error Internal if (table.options.reactivity?.header === false) { return } - setReactivePropertiesOnObject(table.get, prototype, { + // @ts-expect-error Internal + setReactivePropertiesOnObject(table.value, prototype, { skipProperty: getUserSkipPropertyFn( + // @ts-expect-error Internal table.options.reactivity?.cell, skipBaseProperties, ), overridePrototype: true, + factory, }) }, assignRowPrototype: (prototype, table) => { + // @ts-expect-error Internal if (table.options.reactivity?.row === false) { return } - setReactivePropertiesOnObject(table.get, prototype, { + // @ts-expect-error Internal + setReactivePropertiesOnObject(table.value, prototype, { skipProperty: getUserSkipPropertyFn( + // @ts-expect-error Internal table.options.reactivity?.cell, skipBaseProperties, ), overridePrototype: true, + factory, }) }, } } -/** - * Angular reactivity feature that add reactive signal supports in table core instance. - * This is used internally by the Angular table adapter `injectTable`. - * - * @private - */ -export const angularReactivityFeature = constructAngularReactivityFeature() - /** * Default predicate used to skip base/non-reactive properties. */ diff --git a/packages/angular-table/src/reactivityUtils.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts similarity index 83% rename from packages/angular-table/src/reactivityUtils.ts rename to packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts index 1f64f7355c..c2b4588330 100644 --- a/packages/angular-table/src/reactivityUtils.ts +++ b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts @@ -1,7 +1,6 @@ -import { computed, isSignal } from '@angular/core' -import { $internalMemoFnMeta, getMemoFnMeta } from '@tanstack/table-core' +import { $internalMemoFnMeta, getMemoFnMeta } from '../../utils' import type { MemoFnMeta } from '@tanstack/table-core' -import type { Signal } from '@angular/core' +import type { ReactivityFeatureFactoryOptions } from './tableReactivityFeature' const $TABLE_REACTIVE = Symbol('reactive') @@ -13,6 +12,8 @@ function isReactive(obj: T): boolean { return Reflect.get(obj as {}, $TABLE_REACTIVE) === true } +export type Accessor = () => T + /** * Defines a lazy computed property on an object. The property is initialized * with a getter that computes its value only when accessed for the first time. @@ -22,25 +23,26 @@ function isReactive(obj: T): boolean { * @internal should be used only internally */ export function defineLazyComputedProperty( - notifier: Signal, + notifier: Accessor, setObjectOptions: { originalObject: T property: keyof T & string valueFn: (...args: any) => any overridePrototype?: boolean + factory: ReactivityFeatureFactoryOptions }, ) { - const { originalObject, property, overridePrototype, valueFn } = + const { originalObject, property, overridePrototype, valueFn, factory } = setObjectOptions if (overridePrototype) { - assignReactivePrototypeAPI(notifier, originalObject, property) + assignReactivePrototypeAPI(notifier, originalObject, property, factory) } else { Object.defineProperty(originalObject, property, { enumerable: true, configurable: true, get() { - const computedValue = toComputed(notifier, valueFn, property) + const computedValue = toComputed(notifier, valueFn, property, factory) markReactive(computedValue) // Once the property is set the first time, we don't need a getter anymore // since we have a computed / cached fn value @@ -59,7 +61,7 @@ export function defineLazyComputedProperty( * @internal should be used only internally */ type ComputedFunction = T extends () => infer TReturn - ? Signal + ? Accessor : // 1+ args T extends (arg0?: any, ...args: Array) => any ? T @@ -85,26 +87,25 @@ export function toComputed< TReturn, TFunction extends (...args: any) => TReturn, >( - notifier: Signal, + notifier: Accessor, fn: TFunction, debugName: string, + factory: ReactivityFeatureFactoryOptions, ): ComputedFunction { + const { createMemo } = factory const hasArgs = getFnArgsLength(fn) > 0 if (!hasArgs) { - const computedFn = computed( - () => { - void notifier() - return fn() - }, - { debugName }, - ) + const computedFn = createMemo(() => { + void notifier() + return fn() + }) Object.defineProperty(computedFn, 'name', { value: debugName }) markReactive(computedFn) return computedFn as ComputedFunction } const computedFn: ((this: unknown, ...argsArray: Array) => unknown) & { - _reactiveCache?: Record> + _reactiveCache?: Record> } = function (this: unknown, ...argsArray: Array) { const cacheable = argsArray.length === 0 || @@ -125,13 +126,10 @@ export function toComputed< if ((computedFn._reactiveCache ??= {})[serializedArgs]) { return computedFn._reactiveCache[serializedArgs]() } - const computedSignal = computed( - () => { - void notifier() - return fn.apply(this, argsArray) - }, - { debugName }, - ) + const computedSignal = createMemo(() => { + void notifier() + return fn.apply(this, argsArray) + }) computedFn._reactiveCache[serializedArgs] = computedSignal @@ -155,12 +153,15 @@ function getFnArgsLength( } function assignReactivePrototypeAPI( - notifier: Signal, + notifier: Accessor, prototype: Record, fnName: string, + factory: ReactivityFeatureFactoryOptions, ) { if (isReactive(prototype[fnName])) return + const { createMemo } = factory + const fn = prototype[fnName] const originalArgsLength = getFnArgsLength(fn) @@ -173,13 +174,11 @@ function assignReactivePrototypeAPI( // Create a cache in the current prototype to allow the signals // to be garbage collected. Shorthand for a WeakMap implementation self._reactiveCache ??= {} - const cached = (self._reactiveCache[`${self.id}${fnName}`] ??= computed( - () => { + const cached = (self._reactiveCache[`${self.id}${fnName}`] ??= + createMemo(() => { notifier() return fn.apply(self) - }, - {}, - )) + })) markReactive(cached) cached[$internalMemoFnMeta] = { originalArgsLength, @@ -200,14 +199,15 @@ function assignReactivePrototypeAPI( } export function setReactivePropertiesOnObject( - notifier: Signal, + notifier: Accessor, obj: { [key: string]: any }, options: { overridePrototype?: boolean skipProperty: (property: string) => boolean + factory: ReactivityFeatureFactoryOptions }, ) { - const { skipProperty } = options + const { skipProperty, factory } = options if (isReactive(obj)) { return } @@ -215,11 +215,7 @@ export function setReactivePropertiesOnObject( for (const property in obj) { const value = obj[property] - if ( - isSignal(value) || - typeof value !== 'function' || - skipProperty(property) - ) { + if (typeof value !== 'function' || skipProperty(property)) { continue } defineLazyComputedProperty(notifier, { @@ -227,6 +223,7 @@ export function setReactivePropertiesOnObject( property, originalObject: obj, overridePrototype: options.overridePrototype, + factory: factory, }) } } diff --git a/packages/table-core/src/index.ts b/packages/table-core/src/index.ts index ffab1bfbf2..099953ad94 100755 --- a/packages/table-core/src/index.ts +++ b/packages/table-core/src/index.ts @@ -78,6 +78,10 @@ export * from './fns/sortFns' export * from './features/stockFeatures' +// tableReactivityFeature +export * from './features/table-reactivity/tableReactivityFeature' +export * from './features/table-reactivity/tableReactivityFeature.utils' + // columnFacetingFeature export * from './features/column-faceting/columnFacetingFeature' export * from './features/column-faceting/columnFacetingFeature.types' From b24427ff327c4d984efd9d3687f2548f182d9555 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Fri, 27 Feb 2026 22:44:03 +0100 Subject: [PATCH 08/18] feat: refactor reactivity feature with notifier impl --- packages/angular-table/src/injectTable.ts | 63 +++-- .../tests/angularReactivityFeature.test.ts | 31 +- .../flex-render/flex-render-table.test.ts | 2 +- .../angular-table/tests/injectTable.test.ts | 2 +- packages/solid-table/src/createTable.ts | 68 +---- packages/solid-table/tsconfig.json | 2 +- .../src/core/table/constructTable.ts | 1 + .../tableReactivityFeature.ts | 267 ++---------------- .../tableReactivityFeature.utils.ts | 229 --------------- packages/table-core/src/index.ts | 1 - 10 files changed, 102 insertions(+), 564 deletions(-) delete mode 100644 packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index c50bac00c0..90386f6c21 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -2,8 +2,8 @@ import { Injector, assertInInjectionContext, computed, + effect, inject, - isSignal, signal, untracked, } from '@angular/core' @@ -31,6 +31,10 @@ export type AngularTable< * The selected state from the table store, based on the selector provided. */ readonly state: Signal> + /** + * A signal that returns the entire table instance. Will update on table/options change. + */ + readonly value: Signal> /** * Subscribe to changes in the table store with a custom selector. */ @@ -108,17 +112,13 @@ export function injectTable< assertInInjectionContext(injectTable) const injector = inject(Injector) - const angularReactivityFeature = constructReactivityFeature({ - createSignal: (value) => { - return signal(value) as any - }, - createMemo: (fn) => { - return computed(() => fn()) - }, - isSignal: (value) => isSignal(value), - }) - return lazyInit(() => { + const stateNotifier = signal(0) + + const angularReactivityFeature = constructReactivityFeature({ + stateNotifier: stateNotifier, + }) + const resolvedOptions: TableOptions = { ...options(), _features: { @@ -127,14 +127,17 @@ export function injectTable< }, } as TableOptions - const table: AngularTable = constructTable( - resolvedOptions, - ) as AngularTable + const table = constructTable(resolvedOptions) as AngularTable< + TFeatures, + TData, + TSelected + > const updatedOptions = computed>(() => { const tableOptionsValue = options() + const currentOptions = table.options const result: TableOptions = { - ...table.options, + ...currentOptions, ...tableOptionsValue, _features: { ...tableOptionsValue._features, @@ -152,19 +155,32 @@ export function injectTable< (state: TableState) => state, { injector }, ) + const tableOptions = injectStore(table.baseOptionsStore, (state) => state, { + injector, + }) - const tableSignalNotifier = computed( + effect( () => { - tableState() const newOptions = updatedOptions() untracked(() => table.setOptions(newOptions)) untracked(() => table.baseStore.setState((prev) => ({ ...prev }))) - return table }, - { equal: () => false }, + { injector }, ) - table.setTableNotifier(tableSignalNotifier) + let firstRun = true + effect( + () => { + void tableState() + void tableOptions() + if (firstRun) { + firstRun = false + return + } + untracked(() => stateNotifier.update((n) => n + 1)) + }, + { injector }, + ) table.Subscribe = function Subscribe(props: { selector: (state: TableState) => TSubSelected @@ -180,6 +196,13 @@ export function injectTable< value: injectStore(table.store, selector, { injector }), }) + Object.defineProperty(table, 'value', { + value: computed(() => { + stateNotifier() + return table + }), + }) + return table }) } diff --git a/packages/angular-table/tests/angularReactivityFeature.test.ts b/packages/angular-table/tests/angularReactivityFeature.test.ts index f2de587be1..cf7acbd8bb 100644 --- a/packages/angular-table/tests/angularReactivityFeature.test.ts +++ b/packages/angular-table/tests/angularReactivityFeature.test.ts @@ -44,7 +44,7 @@ describe('angularReactivityFeature', () => { const table = createTestTable() const tablePropertyKeys = Object.keys(table) - describe('Table property reactivity', () => { + describe.skip('Table property reactivity', () => { test.each( tablePropertyKeys.map((property) => [ property, @@ -74,7 +74,7 @@ describe('angularReactivityFeature', () => { }) }) - describe('Header property reactivity', () => { + describe.skip('Header property reactivity', () => { const headers = table.getHeaderGroups() headers.forEach((headerGroup, index) => { const headerPropertyKeys = Object.keys(headerGroup) @@ -112,7 +112,7 @@ describe('angularReactivityFeature', () => { }) }) - describe('Column property reactivity', () => { + describe.skip('Column property reactivity', () => { const columns = table.getAllColumns() columns.forEach((column, index) => { const columnPropertyKeys = Object.keys(column).concat( @@ -133,7 +133,7 @@ describe('angularReactivityFeature', () => { }) }) - describe('Row and cells property reactivity', () => { + describe.skip('Row and cells property reactivity', () => { const flatRows = table.getRowModel().flatRows flatRows.forEach((row, index) => { const rowsPropertyKeys = Object.keys(row).concat( @@ -179,6 +179,7 @@ describe('angularReactivityFeature', () => { const table = createTestTable(data) const isSelectedRow1Captor = vi.fn<(val: boolean) => void>() const cellGetValueCaptor = vi.fn<(val: unknown) => void>() + const cellGetValueMemoizedCaptor = vi.fn<(val: unknown) => void>() const columnIsVisibleCaptor = vi.fn<(val: boolean) => void>() // This will test a case where you put in the effect a single cell property method @@ -188,6 +189,8 @@ describe('angularReactivityFeature', () => { () => table.getRowModel().rows[0]!.getAllCells()[0]!, ) + const cellGetValue = computed(() => cell().getValue()) + TestBed.runInInjectionContext(() => { effect(() => { isSelectedRow1Captor(cell().row.getIsSelected()) @@ -195,6 +198,9 @@ describe('angularReactivityFeature', () => { effect(() => { cellGetValueCaptor(cell().getValue()) }) + effect(() => { + cellGetValueMemoizedCaptor(cellGetValue()) + }) effect(() => { columnIsVisibleCaptor(cell().column.getIsVisible()) }) @@ -202,6 +208,7 @@ describe('angularReactivityFeature', () => { TestBed.tick() expect(isSelectedRow1Captor).toHaveBeenCalledTimes(1) + expect(cellGetValueMemoizedCaptor).toHaveBeenCalledTimes(1) expect(cellGetValueCaptor).toHaveBeenCalledTimes(1) expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(1) @@ -209,7 +216,7 @@ describe('angularReactivityFeature', () => { TestBed.tick() expect(isSelectedRow1Captor).toHaveBeenCalledTimes(2) expect(cellGetValueCaptor).toHaveBeenCalledTimes(1) - expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(1) + expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(2) data.set([{ id: '1', title: 'Title 3' }]) TestBed.tick() @@ -217,17 +224,23 @@ describe('angularReactivityFeature', () => { // the cell instance will be recreated expect(isSelectedRow1Captor).toHaveBeenCalledTimes(3) expect(cellGetValueCaptor).toHaveBeenCalledTimes(2) - expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(2) + expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(3) cell().column.toggleVisibility(false) TestBed.tick() - expect(isSelectedRow1Captor).toHaveBeenCalledTimes(3) + expect(isSelectedRow1Captor).toHaveBeenCalledTimes(4) expect(cellGetValueCaptor).toHaveBeenCalledTimes(2) - expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(3) + expect(columnIsVisibleCaptor).toHaveBeenCalledTimes(4) - expect(isSelectedRow1Captor.mock.calls).toEqual([[false], [true], [true]]) + expect(isSelectedRow1Captor.mock.calls).toEqual([ + [false], + [true], + [true], + [true], + ]) expect(cellGetValueCaptor.mock.calls).toEqual([['1'], ['1']]) expect(columnIsVisibleCaptor.mock.calls).toEqual([ + [true], [true], [true], [false], diff --git a/packages/angular-table/tests/flex-render/flex-render-table.test.ts b/packages/angular-table/tests/flex-render/flex-render-table.test.ts index 4781734d6c..3312226c78 100644 --- a/packages/angular-table/tests/flex-render/flex-render-table.test.ts +++ b/packages/angular-table/tests/flex-render/flex-render-table.test.ts @@ -319,7 +319,7 @@ describe('FlexRenderDirective', () => { callExpandRender() return flexRenderComponent(ExpandCell, { bindings: [ - inputBinding('expanded', row.getIsExpanded), + inputBinding('expanded', () => row.getIsExpanded()), outputBinding('toggleExpand', () => row.toggleExpanded()), ], }) diff --git a/packages/angular-table/tests/injectTable.test.ts b/packages/angular-table/tests/injectTable.test.ts index e2700dcb8a..bd6e4d17e0 100644 --- a/packages/angular-table/tests/injectTable.test.ts +++ b/packages/angular-table/tests/injectTable.test.ts @@ -75,7 +75,7 @@ describe('injectTable', () => { }) test('supports "Object.keys"', () => { - const keys = Object.keys(table.value()).concat('state') + const keys = Object.keys(table.value()).concat('state', 'value') expect(Object.keys(table)).toEqual(keys) }) diff --git a/packages/solid-table/src/createTable.ts b/packages/solid-table/src/createTable.ts index 13f68366be..bc877b9bf8 100644 --- a/packages/solid-table/src/createTable.ts +++ b/packages/solid-table/src/createTable.ts @@ -3,14 +3,7 @@ import { constructTable, } from '@tanstack/table-core' import { useStore } from '@tanstack/solid-store' -import { - createComputed, - createMemo, - createSignal, - getOwner, - mergeProps, - runWithOwner, -} from 'solid-js' +import { createComputed, createSignal, mergeProps } from 'solid-js' import type { Accessor, JSX } from 'solid-js' import type { NoInfer, @@ -64,25 +57,10 @@ export function createTable< selector: (state: TableState) => TSelected = () => ({}) as TSelected, ): SolidTable { - const owner = getOwner() + const [notifier, setNotifier] = createSignal(void 0, { equals: false }) const solidReactivityFeature = constructReactivityFeature({ - createSignal: (value) => { - const signal = createSignal(value) - function interoperableSignal() { - return signal[0]() - } - return Object.assign(interoperableSignal, { - set: (value: any) => signal[1](() => value), - }) - }, - createMemo: (fn) => { - if (owner) { - return runWithOwner(owner, () => createMemo(fn))! - } - return createMemo(fn) - }, - isSignal: (value) => typeof value === 'function', + stateNotifier: notifier, }) const mergedOptions = mergeProps(tableOptions, { @@ -91,8 +69,6 @@ export function createTable< }), }) as any - const [renderVersion, setRenderVersion] = createSignal(0) - const resolvedOptions = mergeProps( { mergeOptions: ( @@ -111,15 +87,6 @@ export function createTable< TSelected > - // @ts-ignore - table.setTableNotifier(() => { - renderVersion() - return table - }) - - /** - * Temp force reactivity to all state changes on every table.get* method - */ const allState = useStore(table.store, (state) => state) const allOptions = useStore(table.baseOptionsStore, (options) => options) @@ -133,36 +100,9 @@ export function createTable< // Access storeState to create reactive dependency allState() allOptions() - // Increment version to invalidate cached get* methods - setRenderVersion((v) => v + 1) - // Update options when store changes - // table.setOptions((prev) => { - // return mergeProps(prev, tableOptions) as TableOptions - // }) + setNotifier(void 0) }) - // Object.assign(table, { - // get options() { - // allOptions() - // return table.baseOptionsStore.get() - // }, - // }) - // - // Object.defineProperty(table.store, 'get', { - // value: () => { - // allState() - // allOptions() - // return table.store['atom'].get() - // }, - // }) - // Object.defineProperty(table.store, 'state', { - // get() { - // allState() - // allOptions() - // return this['atom'].get() - // }, - // }) - table.Subscribe = function Subscribe(props: { selector: (state: TableState) => TSelected children: ((state: Accessor) => JSX.Element) | JSX.Element diff --git a/packages/solid-table/tsconfig.json b/packages/solid-table/tsconfig.json index 5f7748754b..2a9da197cd 100644 --- a/packages/solid-table/tsconfig.json +++ b/packages/solid-table/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "jsx": "preserve", - "jsxImportSource": "solid-js" + "jsxImportSource": "solid-js", }, "include": ["src", "eslint.config.js", "vite.config.ts"] } diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index 0b94cc6f85..90c34e9713 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -66,6 +66,7 @@ export function constructTable< const state = table.baseStore.state return { ...state, + // Table `store` will be updated also on options change ...(table.options.state ?? {}), } }) diff --git a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts index 15a3360a23..4b4edde2d3 100644 --- a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts +++ b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts @@ -1,253 +1,44 @@ -import { setReactivePropertiesOnObject } from './tableReactivityFeature.utils' -import type { Accessor } from './tableReactivityFeature.utils' -import type { - RowData, - Table, - TableFeature, - TableFeatures, -} from '@tanstack/table-core' +import type { RowData, TableFeature, TableFeatures } from '@tanstack/table-core' +import type { ReadonlyStore, Store } from '@tanstack/store' -/** - * Predicate used to skip/ignore a property name when applying Angular reactivity. - * - * Returning `true` means the property should NOT be wrapped/made reactive. - */ -type SkipPropertyFn = (property: string) => boolean - -/** - * Fine-grained configuration for Angular reactivity. - * - * Each key controls whether prototype methods/getters on the corresponding TanStack Table - * objects are wrapped with signal-aware access. - * - * - `true` enables wrapping using the default skip rules. - * - `false` disables wrapping entirely for that object type. - * - a function allows customizing the skip rules (see {@link SkipPropertyFn}). - * - * @example - * ```ts - * const table = injectTable(() => { - * // ...table options, - * reactivity: { - * // fine-grained control over which table objects have reactive properties, - * // and which properties are wrapped - * header: true, - * column: true, - * row: true, - * cell: true, - * } - * }) - * ``` - */ -export interface AngularReactivityFlags { - /** Controls reactive wrapping for `Header` instances. */ - header: boolean | SkipPropertyFn - /** Controls reactive wrapping for `Column` instances. */ - column: boolean | SkipPropertyFn - /** Controls reactive wrapping for `Row` instances. */ - row: boolean | SkipPropertyFn - /** Controls reactive wrapping for `Cell` instances. */ - cell: boolean | SkipPropertyFn -} - -/** - * Table option extension for Angular reactivity. - * - * Available on `createTable` options via module augmentation in this file. - */ -interface TableOptions_Reactivity { - /** - * Enables/disables and configures Angular reactivity on table-related prototypes. - * - * If omitted, defaults are provided by the feature. - */ - reactivity?: Partial -} - -/** - * Table API extension for Angular reactivity. - * - * Added to the table instance via module augmentation. - */ -interface Table_Reactivity< - TFeatures extends TableFeatures, - TData extends RowData, -> { - /** - * Returns a table signal that updates whenever the table state or options changes. - */ - value: Accessor> - /** - * Sets the reactive notifier that powers {@link get}. - * - * @internal Used by the Angular table adapter to connect its notifier to the core table. - */ - setTableNotifier: (signal: Accessor>) => void -} - -/** - * Type map describing what this feature adds to TanStack Table constructors. - */ interface TableReactivityFeatureConstructors< TFeatures extends TableFeatures, TData extends RowData, -> { - TableOptions: TableOptions_Reactivity - Table: Table_Reactivity -} - -/** - * Resolves the user-provided `reactivity.*` config to a skip predicate. - * - * - `false` is handled by callers (feature method returns early) - * - `true` selects the default predicate - * - a function overrides the default predicate - */ -const getUserSkipPropertyFn = ( - value: undefined | null | boolean | SkipPropertyFn, - defaultPropertyFn: SkipPropertyFn, -) => { - if (typeof value === 'boolean') { - return defaultPropertyFn - } - - return value ?? defaultPropertyFn -} - -export type InteroperableWritableSignal = { - (): T - set: (value: unknown) => void -} - -export interface ReactivityFeatureFactoryOptions { - createSignal: (value: T) => InteroperableWritableSignal - createMemo: (accessor: Accessor) => Accessor - isSignal: (v: unknown) => boolean -} +> {} export function constructReactivityFeature< TFeatures extends TableFeatures, TData extends RowData, ->( - factory: ReactivityFeatureFactoryOptions, -): TableFeature> { - const { createSignal, createMemo } = factory - +>(bindings: { + stateNotifier: () => unknown +}): TableFeature> { return { - getDefaultTableOptions(table) { - return { - reactivity: { - header: true, - column: true, - row: true, - cell: true, - }, - } - }, constructTableAPIs: (table) => { - const rootNotifier = createSignal - > | null>(null) - - table.setTableNotifier = (notifier) => { - rootNotifier.set(notifier) - } - - table.value = () => { - const notifier = rootNotifier() - void notifier?.() - return table as any - } - - setReactivePropertiesOnObject(table.value, table, { - overridePrototype: false, - skipProperty: skipBaseProperties, - factory, - }) - }, - - assignCellPrototype: (prototype, table) => { - // @ts-expect-error Internal - if (table.options.reactivity?.cell === false) { - return - } - // @ts-expect-error Internal - setReactivePropertiesOnObject(table.value, prototype, { - skipProperty: getUserSkipPropertyFn( - // @ts-expect-error Internal - table.options.reactivity?.cell, - skipBaseProperties, - ), - overridePrototype: true, - factory, - }) - }, - - assignColumnPrototype: (prototype, table) => { - // @ts-expect-error Internal - if (table.options.reactivity?.column === false) { - return - } - // @ts-expect-error Internal - setReactivePropertiesOnObject(table.value, prototype, { - skipProperty: getUserSkipPropertyFn( - // @ts-expect-error Internal - table.options.reactivity?.cell, - skipBaseProperties, - ), - overridePrototype: true, - factory, - }) - }, - - assignHeaderPrototype: (prototype, table) => { - // @ts-expect-error Internal - if (table.options.reactivity?.header === false) { - return - } - // @ts-expect-error Internal - setReactivePropertiesOnObject(table.value, prototype, { - skipProperty: getUserSkipPropertyFn( - // @ts-expect-error Internal - table.options.reactivity?.cell, - skipBaseProperties, - ), - overridePrototype: true, - factory, - }) - }, - - assignRowPrototype: (prototype, table) => { - // @ts-expect-error Internal - if (table.options.reactivity?.row === false) { - return - } - // @ts-expect-error Internal - setReactivePropertiesOnObject(table.value, prototype, { - skipProperty: getUserSkipPropertyFn( - // @ts-expect-error Internal - table.options.reactivity?.cell, - skipBaseProperties, - ), - overridePrototype: true, - factory, - }) + table.store = bindStore(table.store, bindings.stateNotifier) + // table.baseOptionsStore = bindStore( + // table.baseOptionsStore, + // bindings.optionsNotifier, + // ) }, } } -/** - * Default predicate used to skip base/non-reactive properties. - */ -function skipBaseProperties(property: string): boolean { - return ( - // equals `getContext` - property === 'getContext' || - // start with `_` - property[0] === '_' || - // doesn't start with `get`, but faster - !(property[0] === 'g' && property[1] === 'e' && property[2] === 't') || - // ends with `Handler` - property.endsWith('Handler') - ) +const bindStore = | ReadonlyStore>( + store: T, + notifier: () => unknown, +): T => { + const stateDescriptor = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf(store), + 'state', + )! + + Object.defineProperties(store, { + state: { + get: () => { + notifier() + return stateDescriptor.get!.call(store) + }, + }, + }) + return store } diff --git a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts deleted file mode 100644 index c2b4588330..0000000000 --- a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.utils.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { $internalMemoFnMeta, getMemoFnMeta } from '../../utils' -import type { MemoFnMeta } from '@tanstack/table-core' -import type { ReactivityFeatureFactoryOptions } from './tableReactivityFeature' - -const $TABLE_REACTIVE = Symbol('reactive') - -function markReactive(obj: T): void { - Object.defineProperty(obj, $TABLE_REACTIVE, { value: true }) -} - -function isReactive(obj: T): boolean { - return Reflect.get(obj as {}, $TABLE_REACTIVE) === true -} - -export type Accessor = () => T - -/** - * Defines a lazy computed property on an object. The property is initialized - * with a getter that computes its value only when accessed for the first time. - * After the first access, the computed value is cached, and the getter is - * replaced with a direct property assignment for efficiency. - * - * @internal should be used only internally - */ -export function defineLazyComputedProperty( - notifier: Accessor, - setObjectOptions: { - originalObject: T - property: keyof T & string - valueFn: (...args: any) => any - overridePrototype?: boolean - factory: ReactivityFeatureFactoryOptions - }, -) { - const { originalObject, property, overridePrototype, valueFn, factory } = - setObjectOptions - - if (overridePrototype) { - assignReactivePrototypeAPI(notifier, originalObject, property, factory) - } else { - Object.defineProperty(originalObject, property, { - enumerable: true, - configurable: true, - get() { - const computedValue = toComputed(notifier, valueFn, property, factory) - markReactive(computedValue) - // Once the property is set the first time, we don't need a getter anymore - // since we have a computed / cached fn value - Object.defineProperty(originalObject, property, { - value: computedValue, - configurable: true, - enumerable: true, - }) - return computedValue - }, - }) - } -} - -/** - * @internal should be used only internally - */ -type ComputedFunction = T extends () => infer TReturn - ? Accessor - : // 1+ args - T extends (arg0?: any, ...args: Array) => any - ? T - : never - -/** - * @description Transform a function into a computed that react to given notifier re-computations - * - * Here we'll handle all type of accessors: - * - 0 argument -> e.g. table.getCanNextPage()) - * - 0~1 arguments -> e.g. table.getIsSomeRowsPinned(position?) - * - 1 required argument -> e.g. table.getColumn(columnId) - * - 1+ argument -> e.g. table.getRow(id, searchAll?) - * - * Since we are not able to detect automatically the accessors parameters, - * we'll wrap all accessors into a cached function wrapping a computed - * that return it's value based on the given parameters - * - * @internal should be used only internally - */ -export function toComputed< - T, - TReturn, - TFunction extends (...args: any) => TReturn, ->( - notifier: Accessor, - fn: TFunction, - debugName: string, - factory: ReactivityFeatureFactoryOptions, -): ComputedFunction { - const { createMemo } = factory - const hasArgs = getFnArgsLength(fn) > 0 - if (!hasArgs) { - const computedFn = createMemo(() => { - void notifier() - return fn() - }) - Object.defineProperty(computedFn, 'name', { value: debugName }) - markReactive(computedFn) - return computedFn as ComputedFunction - } - - const computedFn: ((this: unknown, ...argsArray: Array) => unknown) & { - _reactiveCache?: Record> - } = function (this: unknown, ...argsArray: Array) { - const cacheable = - argsArray.length === 0 || - argsArray.every((arg) => { - return ( - arg === null || - arg === undefined || - typeof arg === 'string' || - typeof arg === 'number' || - typeof arg === 'boolean' || - typeof arg === 'symbol' - ) - }) - if (!cacheable) { - return fn.apply(this, argsArray) - } - const serializedArgs = serializeArgs(...argsArray) - if ((computedFn._reactiveCache ??= {})[serializedArgs]) { - return computedFn._reactiveCache[serializedArgs]() - } - const computedSignal = createMemo(() => { - void notifier() - return fn.apply(this, argsArray) - }) - - computedFn._reactiveCache[serializedArgs] = computedSignal - - return computedSignal() - } - - Object.defineProperty(computedFn, 'name', { value: debugName }) - markReactive(computedFn) - - return computedFn as ComputedFunction -} - -function serializeArgs(...args: Array) { - return JSON.stringify(args) -} - -function getFnArgsLength( - fn: ((...args: any) => any) & { originalArgsLength?: number }, -): number { - return Math.max(0, getMemoFnMeta(fn)?.originalArgsLength ?? fn.length) -} - -function assignReactivePrototypeAPI( - notifier: Accessor, - prototype: Record, - fnName: string, - factory: ReactivityFeatureFactoryOptions, -) { - if (isReactive(prototype[fnName])) return - - const { createMemo } = factory - - const fn = prototype[fnName] - const originalArgsLength = getFnArgsLength(fn) - - if (originalArgsLength <= 1) { - Object.defineProperty(prototype, fnName, { - enumerable: true, - configurable: true, - get(this) { - const self = this - // Create a cache in the current prototype to allow the signals - // to be garbage collected. Shorthand for a WeakMap implementation - self._reactiveCache ??= {} - const cached = (self._reactiveCache[`${self.id}${fnName}`] ??= - createMemo(() => { - notifier() - return fn.apply(self) - })) - markReactive(cached) - cached[$internalMemoFnMeta] = { - originalArgsLength, - } satisfies MemoFnMeta - return cached - }, - }) - } else { - prototype[fnName] = function (this: unknown, ...args: Array) { - notifier() - return fn.apply(this, args) - } - markReactive(prototype[fnName]) - prototype[fnName][$internalMemoFnMeta] = { - originalArgsLength, - } satisfies MemoFnMeta - } -} - -export function setReactivePropertiesOnObject( - notifier: Accessor, - obj: { [key: string]: any }, - options: { - overridePrototype?: boolean - skipProperty: (property: string) => boolean - factory: ReactivityFeatureFactoryOptions - }, -) { - const { skipProperty, factory } = options - if (isReactive(obj)) { - return - } - markReactive(obj) - - for (const property in obj) { - const value = obj[property] - if (typeof value !== 'function' || skipProperty(property)) { - continue - } - defineLazyComputedProperty(notifier, { - valueFn: value, - property, - originalObject: obj, - overridePrototype: options.overridePrototype, - factory: factory, - }) - } -} diff --git a/packages/table-core/src/index.ts b/packages/table-core/src/index.ts index 099953ad94..656947d3c4 100755 --- a/packages/table-core/src/index.ts +++ b/packages/table-core/src/index.ts @@ -80,7 +80,6 @@ export * from './features/stockFeatures' // tableReactivityFeature export * from './features/table-reactivity/tableReactivityFeature' -export * from './features/table-reactivity/tableReactivityFeature.utils' // columnFacetingFeature export * from './features/column-faceting/columnFacetingFeature' From 32334da36e30a8fde52b7307c3752a7e5754a5fa Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Fri, 27 Feb 2026 22:57:09 +0100 Subject: [PATCH 09/18] feat: try to refactor vue adapter --- packages/vue-table/src/createTableHelper.ts | 6 +-- packages/vue-table/src/useTable.ts | 48 +++++++++++++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/packages/vue-table/src/createTableHelper.ts b/packages/vue-table/src/createTableHelper.ts index fad1c0bd77..57582886ef 100644 --- a/packages/vue-table/src/createTableHelper.ts +++ b/packages/vue-table/src/createTableHelper.ts @@ -12,7 +12,7 @@ import type { export type TableHelper< TFeatures extends TableFeatures, TData extends RowData = any, -> = Omit, 'tableCreator'> & { +> = Omit, 'tableCreator'> & { useTable: ( tableOptions: Omit< TableOptionsWithReactiveData, @@ -26,9 +26,9 @@ export function createTableHelper< TFeatures extends TableFeatures, TData extends RowData, >( - tableHelperOptions: TableHelperOptions, + tableHelperOptions: TableHelperOptions, ): TableHelper { - const tableHelper = constructTableHelper(useTable, tableHelperOptions) + const tableHelper = constructTableHelper(useTable as any, tableHelperOptions) return { ...tableHelper, useTable: ( diff --git a/packages/vue-table/src/useTable.ts b/packages/vue-table/src/useTable.ts index b4d851c878..7381b983c3 100644 --- a/packages/vue-table/src/useTable.ts +++ b/packages/vue-table/src/useTable.ts @@ -1,5 +1,8 @@ -import { isRef, unref, watch } from 'vue' -import { constructTable } from '@tanstack/table-core' +import { isRef, ref, unref, watch } from 'vue' +import { + constructReactivityFeature, + constructTable, +} from '@tanstack/table-core' import { useStore } from '@tanstack/vue-store' import { mergeProxy } from './merge-proxy' import type { @@ -74,8 +77,23 @@ export function useTable< selector: (state: TableState) => TSelected = () => ({}) as TSelected, ): VueTable { + const notifier = ref(0) + + const vueReactivityFeature = constructReactivityFeature({ + stateNotifier: () => notifier.value, + }) const IS_REACTIVE = isRef(tableOptions.data) + tableOptions = { + ...tableOptions, + _features: { + ...tableOptions._features, + vueReactivityFeature, + }, + } + + console.log(tableOptions) + const statefulOptions = mergeProxy( IS_REACTIVE ? getOptionsWithReactiveData(tableOptions) : tableOptions, { @@ -125,24 +143,18 @@ export function useTable< ) } - /** - * Temp force reactivity to all state changes on every table.get* method - */ const allState = useStore(table.store, (state) => state) + const allOptions = useStore(table.baseOptionsStore, (state) => state) - // Wrap all "get*" methods to make them reactive - // Access allState.value directly to create reactive dependency - Object.keys(table).forEach((key) => { - const value = (table as any)[key] - if (typeof value === 'function' && key.startsWith('get')) { - const originalMethod = value.bind(table) - ;(table as any)[key] = (...args: Array) => { - // Access state to create reactive dependency - allState.value - return originalMethod(...args) - } - } - }) + watch( + () => { + return { state: allState.value, options: allOptions.value } + }, + () => { + notifier.value++ + }, + { immediate: true }, + ) table.Subscribe = function Subscribe(props: { selector: (state: TableState) => TSelected From 18ddfbb14eef5515ea6300512f1cf20c8e724ced Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:58:02 +0000 Subject: [PATCH 10/18] ci: apply automated fixes --- packages/solid-table/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/solid-table/tsconfig.json b/packages/solid-table/tsconfig.json index 2a9da197cd..5f7748754b 100644 --- a/packages/solid-table/tsconfig.json +++ b/packages/solid-table/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "jsx": "preserve", - "jsxImportSource": "solid-js", + "jsxImportSource": "solid-js" }, "include": ["src", "eslint.config.js", "vite.config.ts"] } From 37507a78850760e9fca76648e98a2a1f10cd2fd9 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 15:09:49 +0100 Subject: [PATCH 11/18] wip vue adapter --- packages/vue-table/src/useTable.ts | 59 ++++++++++++------------------ pnpm-workspace.yaml | 9 +++-- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/packages/vue-table/src/useTable.ts b/packages/vue-table/src/useTable.ts index 821996251b..6c4375d384 100644 --- a/packages/vue-table/src/useTable.ts +++ b/packages/vue-table/src/useTable.ts @@ -1,4 +1,4 @@ -import { isRef, ref, unref, watch } from 'vue' +import { isRef, ref, unref, watch, watchEffect } from 'vue' import { constructReactivityFeature, constructTable, @@ -82,9 +82,10 @@ export function useTable< const vueReactivityFeature = constructReactivityFeature({ stateNotifier: () => notifier.value, }) + const IS_REACTIVE = isRef(tableOptions.data) - tableOptions = { + const mergedOptions = { ...tableOptions, _features: { ...tableOptions._features, @@ -92,68 +93,54 @@ export function useTable< }, } - console.log(tableOptions) - - const statefulOptions = mergeProxy( - IS_REACTIVE ? getOptionsWithReactiveData(tableOptions) : tableOptions, + const resolvedOptions = mergeProxy( + IS_REACTIVE + ? getOptionsWithReactiveData( + mergedOptions as TableOptions, + ) + : mergedOptions, { // Remove state and onStateChange - store handles it internally mergeOptions: ( defaultOptions: TableOptions, newOptions: Partial>, ) => { - return IS_REACTIVE - ? { - ...defaultOptions, - ...newOptions, - } - : mergeProxy(defaultOptions, newOptions) + return mergeProxy(defaultOptions, newOptions) }, }, ) as TableOptions - const table = constructTable(statefulOptions) as VueTable< + const table = constructTable(resolvedOptions) as VueTable< TFeatures, TData, TSelected > - function updateOptions() { + const allState = useStore(table.store, (state) => state) + const allOptions = useStore(table.optionsStore, (state) => state) + + watchEffect(() => { + console.log('set infinity') table.setOptions((prev) => { return mergeProxy( prev, - IS_REACTIVE ? getOptionsWithReactiveData(tableOptions) : tableOptions, + IS_REACTIVE + ? getOptionsWithReactiveData( + tableOptions as TableOptions, + ) + : tableOptions, ) as TableOptions }) - } - - updateOptions() - - // Add reactivity support for reactive data - if (IS_REACTIVE) { - watch( - () => tableOptions.data, - () => { - table.baseStore.setState((prev: TableState) => ({ - ...prev, - data: unref(tableOptions.data), - })) - }, - { immediate: true }, - ) - } - - const allState = useStore(table.store, (state) => state) - const allOptions = useStore(table.baseOptionsStore, (state) => state) + }) watch( () => { + console.log('update') return { state: allState.value, options: allOptions.value } }, () => { notifier.value++ }, - { immediate: true }, ) table.Subscribe = function Subscribe(props: { diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5add109e67..773f661ccf 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,8 @@ +packages: + - examples/**/* + - packages/* + cleanupUnusedCatalogs: true + linkWorkspacePackages: true preferWorkspacePackages: true - -packages: - - 'examples/**/*' - - 'packages/*' From 6ca67506def6d1eea6ae1a32a90781fbed3f1028 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 15:11:34 +0100 Subject: [PATCH 12/18] wip options as store + some fixes in solid, angular adapter. fix react adapter --- .../angular/row-selection/src/app/app.html | 4 ++ examples/angular/row-selection/src/app/app.ts | 8 ++- .../app/selection-column/selection-column.ts | 1 + examples/solid/row-selection/src/App.tsx | 11 ++-- examples/vue/row-selection/src/App.vue | 13 ++++- packages/angular-table/src/injectTable.ts | 58 ++++++++++--------- packages/react-table/src/useTable.ts | 29 +++------- packages/solid-table/src/createTable.ts | 9 ++- .../src/core/table/constructTable.ts | 15 +++-- .../src/core/table/coreTablesFeature.types.ts | 8 ++- .../src/core/table/coreTablesFeature.utils.ts | 14 ++--- .../tableReactivityFeature.ts | 26 +++++---- packages/table-core/src/utils.ts | 2 +- 13 files changed, 115 insertions(+), 83 deletions(-) diff --git a/examples/angular/row-selection/src/app/app.html b/examples/angular/row-selection/src/app/app.html index a9b5f0461e..35f6a1104b 100644 --- a/examples/angular/row-selection/src/app/app.html +++ b/examples/angular/row-selection/src/app/app.html @@ -1,4 +1,8 @@
+ +
diff --git a/examples/angular/row-selection/src/app/app.ts b/examples/angular/row-selection/src/app/app.ts index 756ab56f20..727c8081ee 100644 --- a/examples/angular/row-selection/src/app/app.ts +++ b/examples/angular/row-selection/src/app/app.ts @@ -32,6 +32,7 @@ export class App { private readonly rowSelection = signal({}) readonly globalFilter = signal('') readonly data = signal(makeData(10_000)) + readonly enableRowSelection = signal(true) readonly columns = columnHelper.columns([ columnHelper.display({ @@ -93,7 +94,8 @@ export class App { state: { rowSelection: this.rowSelection(), }, - enableRowSelection: true, // enable row selection for all rows + + enableRowSelection: this.enableRowSelection(), // enable row selection for all rows // enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row onRowSelectionChange: (updaterOrValue) => { this.rowSelection.set( @@ -136,4 +138,8 @@ export class App { refreshData(): void { this.data.set(makeData(10_000)) } + + toggleEnableRowSelection() { + this.enableRowSelection.update((value) => !value) + } } diff --git a/examples/angular/row-selection/src/app/selection-column/selection-column.ts b/examples/angular/row-selection/src/app/selection-column/selection-column.ts index 5be2238e13..a063cbef41 100644 --- a/examples/angular/row-selection/src/app/selection-column/selection-column.ts +++ b/examples/angular/row-selection/src/app/selection-column/selection-column.ts @@ -29,6 +29,7 @@ export class TableHeaderSelection { `, diff --git a/examples/solid/row-selection/src/App.tsx b/examples/solid/row-selection/src/App.tsx index 7e22049531..93efd2841a 100644 --- a/examples/solid/row-selection/src/App.tsx +++ b/examples/solid/row-selection/src/App.tsx @@ -33,6 +33,7 @@ export const _features = tableFeatures({ function App() { const [data, setData] = createSignal(makeData(1_000)) const refreshData = () => setData(makeData(100_000)) // stress test + const [enableRowSelection, setEnableRowSelection] = createSignal(true) // Create table first with a placeholder for columns let table: SolidTable @@ -117,8 +118,6 @@ function App() { }, ] - const [enableRowSelection, setEnableRowSelection] = createSignal(true) - table = createTable({ _features, _rowModels: { @@ -136,8 +135,6 @@ function App() { debugTable: true, }) - window.setEnable = setEnableRowSelection - return ( // ({ @@ -336,6 +333,12 @@ function App() { > Log table.getSelectedRowModel().flatRows +
diff --git a/examples/vue/row-selection/src/App.vue b/examples/vue/row-selection/src/App.vue index 58501f58c8..791e73ec67 100644 --- a/examples/vue/row-selection/src/App.vue +++ b/examples/vue/row-selection/src/App.vue @@ -88,18 +88,26 @@ const columns = columnHelper.columns([ ]) const data = ref(makeData(10)) +const enableRowSelection = ref(true) const rerender = () => { data.value = makeData(10) } +const toggleRowSelection = () => { + enableRowSelection.value = !enableRowSelection.value +} + const table = useTable( { _features, _rowModels: {}, data, columns, - enableRowSelection: true, //enable row selection for all rows + // enable row selection for all rows + get enableRowSelection() { + return enableRowSelection.value + }, // enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row }, (state) => ({ rowSelection: state.rowSelection }), @@ -152,6 +160,9 @@ const table = useTable(
+
diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index 34e432b491..baa541dfd8 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -1,13 +1,18 @@ -import type { Signal, ValueEqualityFn } from '@angular/core' import { + Injector, assertInInjectionContext, computed, effect, inject, - Injector, signal, untracked, } from '@angular/core' +import { + constructReactivityFeature, + constructTable, +} from '@tanstack/table-core' +import { injectStore } from '@tanstack/angular-store' +import { lazyInit } from './lazySignalInitializer' import type { RowData, Table, @@ -15,12 +20,7 @@ import type { TableOptions, TableState, } from '@tanstack/table-core' -import { - constructReactivityFeature, - constructTable, -} from '@tanstack/table-core' -import { injectStore } from '@tanstack/angular-store' -import { lazyInit } from './lazySignalInitializer' +import type { Signal, ValueEqualityFn } from '@angular/core' export type AngularTable< TFeatures extends TableFeatures, @@ -111,12 +111,21 @@ export function injectTable< ): AngularTable { assertInInjectionContext(injectTable) const injector = inject(Injector) + let count = 0 return lazyInit(() => { const stateNotifier = signal(0) const angularReactivityFeature = constructReactivityFeature({ - stateNotifier: stateNotifier, + stateNotifier: () => { + if (count >= 100000) { + // TODO: temp I need to check how to avoid infinite access + throw new Error('Max options access') + } + count++ + + return stateNotifier() + }, }) const resolvedOptions: TableOptions = { @@ -135,7 +144,7 @@ export function injectTable< const updatedOptions = computed>(() => { const tableOptionsValue = options() - const currentOptions = table.options + const currentOptions = table.latestOptions const result: TableOptions = { ...currentOptions, ...tableOptionsValue, @@ -150,34 +159,30 @@ export function injectTable< return result }) - const tableState = injectStore( - table.store, - (state: TableState) => state, - { injector }, - ) - const tableOptions = injectStore(table.baseOptionsStore, (state) => state, { - injector, - }) - effect( () => { const newOptions = updatedOptions() untracked(() => table.setOptions(newOptions)) - untracked(() => table.baseStore.setState((prev) => ({ ...prev }))) }, { injector }, ) + const tableState = injectStore(table.store, (state) => state, { injector }) + const tableOptions = injectStore(table.optionsStore, (state) => state, { + injector, + }) + let firstRun = true effect( () => { - void tableState() - void tableOptions() - if (firstRun) { - firstRun = false - return + tableOptions() + tableState() + if (!firstRun) { + untracked(() => { + stateNotifier.update((n) => n + 1) + }) } - untracked(() => stateNotifier.update((n) => n + 1)) + firstRun = false }, { injector }, ) @@ -191,7 +196,6 @@ export function injectTable< equal: props.equal, }) } - Object.defineProperty(table, 'state', { value: injectStore(table.store, selector, { injector }), }) diff --git a/packages/react-table/src/useTable.ts b/packages/react-table/src/useTable.ts index 60d0685b0b..4f1deb83a0 100644 --- a/packages/react-table/src/useTable.ts +++ b/packages/react-table/src/useTable.ts @@ -2,7 +2,7 @@ import { useEffect, useLayoutEffect, useMemo, useState } from 'react' import { constructTable } from '@tanstack/table-core' -import { useStore } from '@tanstack/react-store' +import { shallow, useStore } from '@tanstack/react-store' import { FlexRender } from './FlexRender' import { Subscribe } from './Subscribe' import type { @@ -103,26 +103,15 @@ export function useTable< return tableInstance }) - // sync table options on every render - table.setOptions((prev) => ({ - ...prev, - ...tableOptions, - })) + useEffect(() => { + // sync table options on every render + table.setOptions((prev) => ({ + ...prev, + ...tableOptions, + })) + }, [table, tableOptions]) - useIsomorphicLayoutEffect(() => { - // prevent race condition between table.setOptions and table.baseStore.setState - queueMicrotask(() => { - table.baseStore.setState((prev) => ({ - ...prev, - })) - }) - }, [ - table.options.columns, // re-render when columns change - table.options.data, // re-render when data changes - table.options.state, // sync react state to the table store - ]) - - const state = useStore(table.store, selector) + const state = useStore(table.store, selector, shallow) return useMemo( () => ({ diff --git a/packages/solid-table/src/createTable.ts b/packages/solid-table/src/createTable.ts index bc877b9bf8..b4a9658357 100644 --- a/packages/solid-table/src/createTable.ts +++ b/packages/solid-table/src/createTable.ts @@ -58,9 +58,13 @@ export function createTable< ({}) as TSelected, ): SolidTable { const [notifier, setNotifier] = createSignal(void 0, { equals: false }) + const [optionsNotifier, setOptionsNotifier] = createSignal(void 0, { + equals: false, + }) const solidReactivityFeature = constructReactivityFeature({ - stateNotifier: notifier, + stateNotifier: () => notifier(), + optionsNotifier: () => optionsNotifier(), }) const mergedOptions = mergeProps(tableOptions, { @@ -88,7 +92,7 @@ export function createTable< > const allState = useStore(table.store, (state) => state) - const allOptions = useStore(table.baseOptionsStore, (options) => options) + const allOptions = useStore(table.optionsStore, (options) => options) createComputed(() => { table.setOptions((prev) => { @@ -97,7 +101,6 @@ export function createTable< }) createComputed(() => { - // Access storeState to create reactive dependency allState() allOptions() setNotifier(void 0) diff --git a/packages/table-core/src/core/table/constructTable.ts b/packages/table-core/src/core/table/constructTable.ts index 90c34e9713..35f441c451 100644 --- a/packages/table-core/src/core/table/constructTable.ts +++ b/packages/table-core/src/core/table/constructTable.ts @@ -42,16 +42,20 @@ export function constructTable< return Object.assign(obj, feature.getDefaultTableOptions?.(table)) }, {}) as TableOptions - table.baseOptionsStore = createStore({ + table.latestOptions = { ...defaultOptions, ...tableOptions, - }) - + } + table.optionsStore = createStore(table.latestOptions) Object.defineProperty(table, 'options', { enumerable: true, configurable: true, get() { - return table.baseOptionsStore.state + return table.optionsStore.state + }, + set(value) { + table.latestOptions = value + table.optionsStore.setState(() => value) }, }) @@ -66,7 +70,8 @@ export function constructTable< const state = table.baseStore.state return { ...state, - // Table `store` will be updated also on options change + // Merge state with non-reactive options. + // NOTE: Adapters should call `table.baseStore.setState` to trigger state updates ...(table.options.state ?? {}), } }) diff --git a/packages/table-core/src/core/table/coreTablesFeature.types.ts b/packages/table-core/src/core/table/coreTablesFeature.types.ts index ccb1224ec1..5b692c740f 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.types.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.types.ts @@ -95,13 +95,17 @@ export interface Table_CoreProperties< */ baseStore: Store> /** - * The base store for the table. This can be used to write to the table state. + * The base store for the table options. */ - baseOptionsStore: Store> + optionsStore: Store> /** * This is the resolved initial state of the table. */ initialState: TableState + /** + * The latest table options value (non reactive). + */ + latestOptions: TableOptions /** * A read-only reference to the table's current options. */ diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 436a5f1e88..d897137513 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -18,12 +18,12 @@ export function table_mergeOptions< table: Table_Internal, newOptions: TableOptions, ) { - if (table.options.mergeOptions) { - return table.options.mergeOptions(table.options, newOptions) + if (table.latestOptions.mergeOptions) { + return table.latestOptions.mergeOptions(table.latestOptions, newOptions) } return { - ...table.options, + ...table.latestOptions, ...newOptions, } } @@ -35,8 +35,8 @@ export function table_setOptions< table: Table_Internal, updater: Updater>, ): void { - table.baseOptionsStore.setState((options) => { - const newOptions = functionalUpdate(updater, options) - return table_mergeOptions(table, newOptions) - }) + const newOptions = functionalUpdate(updater, table.latestOptions) + const mergedOptions = table_mergeOptions(table, newOptions) + table.latestOptions = mergedOptions + table.optionsStore.setState(() => mergedOptions) } diff --git a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts index 4b4edde2d3..650e53e35e 100644 --- a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts +++ b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts @@ -10,35 +10,37 @@ export function constructReactivityFeature< TFeatures extends TableFeatures, TData extends RowData, >(bindings: { - stateNotifier: () => unknown + stateNotifier?: () => unknown + optionsNotifier?: () => unknown }): TableFeature> { return { constructTableAPIs: (table) => { table.store = bindStore(table.store, bindings.stateNotifier) - // table.baseOptionsStore = bindStore( - // table.baseOptionsStore, - // bindings.optionsNotifier, - // ) + table.optionsStore = bindStore( + table.optionsStore, + bindings.optionsNotifier, + ) }, } } const bindStore = | ReadonlyStore>( store: T, - notifier: () => unknown, + notifier?: () => unknown, ): T => { const stateDescriptor = Object.getOwnPropertyDescriptor( Object.getPrototypeOf(store), 'state', )! - Object.defineProperties(store, { - state: { - get: () => { - notifier() - return stateDescriptor.get!.call(store) - }, + Object.defineProperty(store, 'state', { + configurable: true, + enumerable: true, + get() { + notifier?.() + return stateDescriptor.get!.call(store) }, }) + return store } diff --git a/packages/table-core/src/utils.ts b/packages/table-core/src/utils.ts index d8325b6f72..18877a09f3 100755 --- a/packages/table-core/src/utils.ts +++ b/packages/table-core/src/utils.ts @@ -16,7 +16,7 @@ export function makeStateUpdater< K extends (string & {}) | keyof TableState_All | keyof TableState, >(key: K, instance: Table) { return (updater: Updater[K & keyof TableState]>) => { - ;(instance as Table_Internal).baseStore.setState( + instance.baseStore.setState( (old: TTableState) => { return { ...old, From 60e4aaecc82114e47e1b9b668739a4a923ed4061 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 20:08:54 +0100 Subject: [PATCH 13/18] fix vue adapter --- packages/vue-table/src/useTable.ts | 36 +++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/vue-table/src/useTable.ts b/packages/vue-table/src/useTable.ts index 6c4375d384..8d6ef2bfdf 100644 --- a/packages/vue-table/src/useTable.ts +++ b/packages/vue-table/src/useTable.ts @@ -81,6 +81,7 @@ export function useTable< const vueReactivityFeature = constructReactivityFeature({ stateNotifier: () => notifier.value, + optionsNotifier: () => notifier.value, }) const IS_REACTIVE = isRef(tableOptions.data) @@ -120,27 +121,30 @@ export function useTable< const allOptions = useStore(table.optionsStore, (state) => state) watchEffect(() => { - console.log('set infinity') - table.setOptions((prev) => { - return mergeProxy( - prev, - IS_REACTIVE - ? getOptionsWithReactiveData( - tableOptions as TableOptions, - ) - : tableOptions, - ) as TableOptions - }) + allState.value + allOptions.value + notifier.value++ }) watch( + () => + [ + IS_REACTIVE ? unref(tableOptions.data) : tableOptions.data, + tableOptions, + ] as const, () => { - console.log('update') - return { state: allState.value, options: allOptions.value } - }, - () => { - notifier.value++ + table.setOptions((prev) => { + return mergeProxy( + prev, + IS_REACTIVE + ? getOptionsWithReactiveData( + tableOptions as TableOptions, + ) + : tableOptions, + ) as TableOptions + }) }, + { immediate: true }, ) table.Subscribe = function Subscribe(props: { From d05a17eda5cba45e8edc6f92cc92be7b70222a0e Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 20:10:49 +0100 Subject: [PATCH 14/18] fix types --- .../src/features/table-reactivity/tableReactivityFeature.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts index 650e53e35e..fc63235138 100644 --- a/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts +++ b/packages/table-core/src/features/table-reactivity/tableReactivityFeature.ts @@ -1,4 +1,5 @@ -import type { RowData, TableFeature, TableFeatures } from '@tanstack/table-core' +import type { TableFeature, TableFeatures } from '../../types/TableFeatures' +import type { RowData } from '../../types/type-utils' import type { ReadonlyStore, Store } from '@tanstack/store' interface TableReactivityFeatureConstructors< From 40e43b29dba3734523740f92a82d05cdba482e1f Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 20:13:38 +0100 Subject: [PATCH 15/18] fix table devtools --- packages/table-devtools/src/TableContextProvider.tsx | 6 +++--- packages/table-devtools/src/components/OptionsPanel.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/table-devtools/src/TableContextProvider.tsx b/packages/table-devtools/src/TableContextProvider.tsx index 2208cf9401..fec237bc3c 100644 --- a/packages/table-devtools/src/TableContextProvider.tsx +++ b/packages/table-devtools/src/TableContextProvider.tsx @@ -1,4 +1,3 @@ -import type { Accessor, ParentComponent, Setter } from 'solid-js' import { createContext, createEffect, @@ -10,7 +9,8 @@ import { getTableDevtoolsTarget, subscribeTableDevtoolsTarget, } from './tableTarget' -import type { RowData, Table, TableFeatures } from '@tanstack/table-core' +import type { Accessor, ParentComponent, Setter } from 'solid-js' +import type { RowData, Table, stockFeatures } from '@tanstack/table-core' export type TableDevtoolsTabId = | 'features' @@ -18,7 +18,7 @@ export type TableDevtoolsTabId = | 'options' | 'rows' | 'columns' -type AnyTable = Table +type AnyTable = Table interface TableDevtoolsContextValue { table: Accessor diff --git a/packages/table-devtools/src/components/OptionsPanel.tsx b/packages/table-devtools/src/components/OptionsPanel.tsx index 011be836e8..8bd669db21 100644 --- a/packages/table-devtools/src/components/OptionsPanel.tsx +++ b/packages/table-devtools/src/components/OptionsPanel.tsx @@ -11,7 +11,7 @@ export function OptionsPanel() { const tableInstance = table() const tableState = tableInstance ? useStore( - tableInstance.baseOptionsStore, + tableInstance.optionsStore, ({ state, data, _features, _rowModels, ...options }) => options, ) : undefined From e225ac49bb416234075e02476467efa731cb6d3c Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 20:22:35 +0100 Subject: [PATCH 16/18] fix lint --- examples/solid/row-selection/package.json | 2 +- .../src/SolidTableDevtools.tsx | 4 ++-- packages/solid-table-devtools/src/index.ts | 17 +++++++---------- packages/solid-table-devtools/src/plugin.tsx | 1 - packages/solid-table-devtools/src/production.ts | 2 -- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/examples/solid/row-selection/package.json b/examples/solid/row-selection/package.json index 8fdf7ab281..d50619480f 100644 --- a/examples/solid/row-selection/package.json +++ b/examples/solid/row-selection/package.json @@ -18,8 +18,8 @@ }, "dependencies": { "@tanstack/solid-table": "^9.0.0-alpha.10", - "@tanstack/solid-devtools": "^0.7.26", "@tanstack/solid-table-devtools": "9.0.0-alpha.11", + "@tanstack/solid-devtools": "^0.7.26", "solid-js": "^1.9.11" } } diff --git a/packages/solid-table-devtools/src/SolidTableDevtools.tsx b/packages/solid-table-devtools/src/SolidTableDevtools.tsx index 2add8e7819..29c1a28712 100644 --- a/packages/solid-table-devtools/src/SolidTableDevtools.tsx +++ b/packages/solid-table-devtools/src/SolidTableDevtools.tsx @@ -1,9 +1,9 @@ -import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid' import { createSolidPanel } from '@tanstack/devtools-utils/solid' import { - setTableDevtoolsTarget, TableDevtoolsCore, + setTableDevtoolsTarget, } from '@tanstack/table-devtools' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' diff --git a/packages/solid-table-devtools/src/index.ts b/packages/solid-table-devtools/src/index.ts index c34bc8c874..6404ae4ecb 100644 --- a/packages/solid-table-devtools/src/index.ts +++ b/packages/solid-table-devtools/src/index.ts @@ -1,17 +1,14 @@ -'use client' - +import { isDev } from 'solid-js/web' import * as Devtools from './SolidTableDevtools' import * as plugin from './plugin' -export const TableDevtoolsPanel = - process.env.NODE_ENV !== 'development' - ? Devtools.TableDevtoolsPanelNoOp - : Devtools.TableDevtoolsPanel +export const TableDevtoolsPanel = !isDev + ? Devtools.TableDevtoolsPanelNoOp + : Devtools.TableDevtoolsPanel -export const tableDevtoolsPlugin = - process.env.NODE_ENV !== 'development' - ? plugin.tableDevtoolsNoOpPlugin - : plugin.tableDevtoolsPlugin +export const tableDevtoolsPlugin = !isDev + ? plugin.tableDevtoolsNoOpPlugin + : plugin.tableDevtoolsPlugin export type { TableDevtoolsSolidInit } from './SolidTableDevtools' export type { TableDevtoolsPluginOptions } from './plugin' diff --git a/packages/solid-table-devtools/src/plugin.tsx b/packages/solid-table-devtools/src/plugin.tsx index dfc00d2760..2133421efe 100644 --- a/packages/solid-table-devtools/src/plugin.tsx +++ b/packages/solid-table-devtools/src/plugin.tsx @@ -1,4 +1,3 @@ -import React from 'react' import { TableDevtoolsPanel } from './SolidTableDevtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' diff --git a/packages/solid-table-devtools/src/production.ts b/packages/solid-table-devtools/src/production.ts index b197295f30..169081c353 100644 --- a/packages/solid-table-devtools/src/production.ts +++ b/packages/solid-table-devtools/src/production.ts @@ -1,5 +1,3 @@ -'use client' - export { TableDevtoolsPanel } from './SolidTableDevtools' export type { TableDevtoolsSolidInit } from './SolidTableDevtools' export { tableDevtoolsPlugin } from './plugin' From daaea7183067b102fbceb17c74418b7ce31281b8 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 22:54:53 +0100 Subject: [PATCH 17/18] fix table devtools --- knip.json | 5 +++- packages/angular-table/src/injectTable.ts | 9 ++------ packages/solid-table-devtools/package.json | 18 ++++++++------- ...lidTableDevtools.tsx => TableDevtools.tsx} | 0 packages/solid-table-devtools/src/index.ts | 4 ++-- packages/solid-table-devtools/src/plugin.tsx | 3 ++- .../solid-table-devtools/src/production.ts | 9 ++++---- .../src/production/TableDevtools.tsx | 10 ++++++++ .../src/production/plugin.tsx | 9 ++++++++ packages/solid-table-devtools/vite.config.ts | 23 +++++++++++++++++-- packages/table-devtools/package.json | 1 - .../src/TableContextProvider.tsx | 7 +----- pnpm-lock.yaml | 5 +--- 13 files changed, 67 insertions(+), 36 deletions(-) rename packages/solid-table-devtools/src/{SolidTableDevtools.tsx => TableDevtools.tsx} (100%) create mode 100644 packages/solid-table-devtools/src/production/TableDevtools.tsx create mode 100644 packages/solid-table-devtools/src/production/plugin.tsx diff --git a/knip.json b/knip.json index d3668b30bf..4c38f1ee81 100644 --- a/knip.json +++ b/knip.json @@ -1,9 +1,12 @@ { "$schema": "https://unpkg.com/knip@5/schema.json", "ignoreDependencies": ["@faker-js/faker"], - "ignoreWorkspaces": ["examples/**", "packages/table-core/tests/**"], + "ignoreWorkspaces": ["examples/**"], "ignore": ["**/*benchmark*", "**/benchmarks/**"], "workspaces": { + "packages/table-core": { + "ignore": ["**/tests/**"] + }, "packages/match-sorter-utils": { "ignoreDependencies": ["remove-accents"] }, diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index baa541dfd8..0f9b53a4c1 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -111,19 +111,14 @@ export function injectTable< ): AngularTable { assertInInjectionContext(injectTable) const injector = inject(Injector) - let count = 0 + const count = 0 return lazyInit(() => { const stateNotifier = signal(0) const angularReactivityFeature = constructReactivityFeature({ + // optionsNotifier: () => stateNotifier(), stateNotifier: () => { - if (count >= 100000) { - // TODO: temp I need to check how to avoid infinite access - throw new Error('Max options access') - } - count++ - return stateNotifier() }, }) diff --git a/packages/solid-table-devtools/package.json b/packages/solid-table-devtools/package.json index eea909e0ab..b8bfaf0765 100644 --- a/packages/solid-table-devtools/package.json +++ b/packages/solid-table-devtools/package.json @@ -27,22 +27,22 @@ "test:lib:dev": "pnpm test:lib --watch", "test:types": "tsc", "test:build": "publint --strict", - "build": "tsc -p tsconfig.build.json" + "build": "vite build" }, "type": "module", - "types": "dist/index.d.ts", - "module": "dist/index.js", + "types": "dist/esm/index.d.ts", + "module": "dist/esm/index.js", "exports": { ".": { "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" } }, "./production": { "import": { - "types": "./dist/production.d.ts", - "default": "./dist/production.js" + "types": "./dist/esm/production.d.ts", + "default": "./dist/esm/production.js" } }, "./package.json": "./package.json" @@ -60,8 +60,10 @@ "@tanstack/table-core": "workspace:*", "@tanstack/table-devtools": "workspace:*" }, + "peerDependencies": { + "solid-js": "^1.9.11" + }, "devDependencies": { - "solid-js": "^1.9.11", "vite-plugin-solid": "^2.11.10" } } diff --git a/packages/solid-table-devtools/src/SolidTableDevtools.tsx b/packages/solid-table-devtools/src/TableDevtools.tsx similarity index 100% rename from packages/solid-table-devtools/src/SolidTableDevtools.tsx rename to packages/solid-table-devtools/src/TableDevtools.tsx diff --git a/packages/solid-table-devtools/src/index.ts b/packages/solid-table-devtools/src/index.ts index 6404ae4ecb..70cdd3bcf1 100644 --- a/packages/solid-table-devtools/src/index.ts +++ b/packages/solid-table-devtools/src/index.ts @@ -1,6 +1,6 @@ import { isDev } from 'solid-js/web' -import * as Devtools from './SolidTableDevtools' import * as plugin from './plugin' +import * as Devtools from './TableDevtools' export const TableDevtoolsPanel = !isDev ? Devtools.TableDevtoolsPanelNoOp @@ -10,5 +10,5 @@ export const tableDevtoolsPlugin = !isDev ? plugin.tableDevtoolsNoOpPlugin : plugin.tableDevtoolsPlugin -export type { TableDevtoolsSolidInit } from './SolidTableDevtools' +export type { TableDevtoolsSolidInit } from './TableDevtools' export type { TableDevtoolsPluginOptions } from './plugin' diff --git a/packages/solid-table-devtools/src/plugin.tsx b/packages/solid-table-devtools/src/plugin.tsx index 2133421efe..07561b9b35 100644 --- a/packages/solid-table-devtools/src/plugin.tsx +++ b/packages/solid-table-devtools/src/plugin.tsx @@ -1,4 +1,5 @@ -import { TableDevtoolsPanel } from './SolidTableDevtools' +import { createSolidPlugin } from '@tanstack/devtools-utils/solid' +import { TableDevtoolsPanel } from './TableDevtools' import type { RowData, Table, TableFeatures } from '@tanstack/table-core' export interface TableDevtoolsPluginOptions< diff --git a/packages/solid-table-devtools/src/production.ts b/packages/solid-table-devtools/src/production.ts index 169081c353..f683bce6b7 100644 --- a/packages/solid-table-devtools/src/production.ts +++ b/packages/solid-table-devtools/src/production.ts @@ -1,4 +1,5 @@ -export { TableDevtoolsPanel } from './SolidTableDevtools' -export type { TableDevtoolsSolidInit } from './SolidTableDevtools' -export { tableDevtoolsPlugin } from './plugin' -export type { TableDevtoolsPluginOptions } from './plugin' +export { TableDevtoolsPanel } from './TableDevtools' + +export type { TableDevtoolsSolidInit } from './production/TableDevtools' + +export { tableDevtoolsPlugin } from './production/plugin' diff --git a/packages/solid-table-devtools/src/production/TableDevtools.tsx b/packages/solid-table-devtools/src/production/TableDevtools.tsx new file mode 100644 index 0000000000..f0a5ef6f4c --- /dev/null +++ b/packages/solid-table-devtools/src/production/TableDevtools.tsx @@ -0,0 +1,10 @@ +import { createSolidPanel } from '@tanstack/devtools-utils/solid' +import { TableDevtoolsCore } from '@tanstack/table-devtools/production' + +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid' + +const [TableDevtoolsPanel] = createSolidPanel(TableDevtoolsCore) + +export interface TableDevtoolsSolidInit extends DevtoolsPanelProps {} + +export { TableDevtoolsPanel } diff --git a/packages/solid-table-devtools/src/production/plugin.tsx b/packages/solid-table-devtools/src/production/plugin.tsx new file mode 100644 index 0000000000..403eedabc3 --- /dev/null +++ b/packages/solid-table-devtools/src/production/plugin.tsx @@ -0,0 +1,9 @@ +import { createSolidPlugin } from '@tanstack/devtools-utils/solid' +import { TableDevtoolsPanel } from './TableDevtools' + +const [tableDevtoolsPlugin] = createSolidPlugin({ + name: 'TanStack Table', + Component: TableDevtoolsPanel, +}) + +export { tableDevtoolsPlugin } diff --git a/packages/solid-table-devtools/vite.config.ts b/packages/solid-table-devtools/vite.config.ts index a872ffe359..8b74746c4c 100644 --- a/packages/solid-table-devtools/vite.config.ts +++ b/packages/solid-table-devtools/vite.config.ts @@ -1,6 +1,25 @@ -import { defineConfig } from 'vitest/config' +import { defineConfig, mergeConfig } from 'vitest/config' +import { tanstackViteConfig } from '@tanstack/vite-config' import solid from 'vite-plugin-solid' +import packageJson from './package.json' -export default defineConfig({ +const config = defineConfig({ plugins: [solid()], + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'jsdom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, }) + +export default mergeConfig( + config, + tanstackViteConfig({ + entry: ['./src/index.ts', './src/production.ts'], + srcDir: './src', + cjs: false, + }), +) diff --git a/packages/table-devtools/package.json b/packages/table-devtools/package.json index 764f5c2e59..083b7ead37 100644 --- a/packages/table-devtools/package.json +++ b/packages/table-devtools/package.json @@ -59,7 +59,6 @@ "@tanstack/devtools-ui": "^0.4.4", "@tanstack/devtools-utils": "^0.3.0", "@tanstack/solid-store": "^0.9.1", - "clsx": "^2.1.1", "goober": "^2.1.18", "solid-js": "^1.9.11" }, diff --git a/packages/table-devtools/src/TableContextProvider.tsx b/packages/table-devtools/src/TableContextProvider.tsx index fec237bc3c..8d043e2b9f 100644 --- a/packages/table-devtools/src/TableContextProvider.tsx +++ b/packages/table-devtools/src/TableContextProvider.tsx @@ -12,12 +12,7 @@ import { import type { Accessor, ParentComponent, Setter } from 'solid-js' import type { RowData, Table, stockFeatures } from '@tanstack/table-core' -export type TableDevtoolsTabId = - | 'features' - | 'state' - | 'options' - | 'rows' - | 'columns' +type TableDevtoolsTabId = 'features' | 'state' | 'options' | 'rows' | 'columns' type AnyTable = Table interface TableDevtoolsContextValue { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 768b85dbc1..9e9a81485f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3618,10 +3618,10 @@ importers: '@tanstack/table-devtools': specifier: workspace:* version: link:../table-devtools - devDependencies: solid-js: specifier: ^1.9.11 version: 1.9.11 + devDependencies: vite-plugin-solid: specifier: ^2.11.10 version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2)) @@ -3671,9 +3671,6 @@ importers: '@tanstack/table-core': specifier: workspace:* version: link:../table-core - clsx: - specifier: ^2.1.1 - version: 2.1.1 goober: specifier: ^2.1.18 version: 2.1.18(csstype@3.2.3) From 74e969657c6e6859a4a82c814eaa59ede0881e90 Mon Sep 17 00:00:00 2001 From: riccardoperra Date: Mon, 2 Mar 2026 23:23:38 +0100 Subject: [PATCH 18/18] fix knip issues --- examples/solid/row-selection/package.json | 4 +- packages/solid-table-devtools/vite.config.ts | 1 - pnpm-lock.yaml | 47 +++++++++++++++++++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/examples/solid/row-selection/package.json b/examples/solid/row-selection/package.json index d50619480f..8ad3256001 100644 --- a/examples/solid/row-selection/package.json +++ b/examples/solid/row-selection/package.json @@ -17,9 +17,9 @@ "vite-plugin-solid": "^2.11.10" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-alpha.10", - "@tanstack/solid-table-devtools": "9.0.0-alpha.11", "@tanstack/solid-devtools": "^0.7.26", + "@tanstack/solid-table": "^9.0.0-alpha.10", + "@tanstack/solid-table-devtools": "workspace:*", "solid-js": "^1.9.11" } } diff --git a/packages/solid-table-devtools/vite.config.ts b/packages/solid-table-devtools/vite.config.ts index 8b74746c4c..896c24e885 100644 --- a/packages/solid-table-devtools/vite.config.ts +++ b/packages/solid-table-devtools/vite.config.ts @@ -10,7 +10,6 @@ const config = defineConfig({ dir: './', watch: false, environment: 'jsdom', - setupFiles: ['./tests/test-setup.ts'], globals: true, }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e9a81485f..93b751d2d3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2782,7 +2782,7 @@ importers: specifier: ^9.0.0-alpha.10 version: link:../../../packages/solid-table '@tanstack/solid-table-devtools': - specifier: 9.0.0-alpha.11 + specifier: workspace:* version: link:../../../packages/solid-table-devtools solid-js: specifier: ^1.9.11 @@ -15724,7 +15724,7 @@ snapshots: '@tanstack/react-router': 1.157.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) vite: 7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2) vite-plugin-solid: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.0.10)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.19.2)(yaml@2.8.2)) - webpack: 5.104.1(esbuild@0.27.2) + webpack: 5.104.1 transitivePeerDependencies: - supports-color @@ -20582,6 +20582,16 @@ snapshots: optionalDependencies: esbuild: 0.27.2 + terser-webpack-plugin@5.3.16(webpack@5.104.1(esbuild@0.27.2)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 + terser: 5.44.1 + webpack: 5.104.1 + optional: true + terser@5.44.1: dependencies: '@jridgewell/source-map': 0.3.6 @@ -21123,6 +21133,39 @@ snapshots: webpack-virtual-modules@0.6.2: {} + webpack@5.104.1: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + acorn-import-phases: 1.0.4(acorn@8.15.0) + browserslist: 4.28.1 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.4 + es-module-lexer: 2.0.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.16(webpack@5.104.1(esbuild@0.27.2)) + watchpack: 2.5.0 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + optional: true + webpack@5.104.1(esbuild@0.27.2): dependencies: '@types/eslint-scope': 3.7.7