diff --git a/frontend/__tests__/components/ui/table/DataTable.spec.tsx b/frontend/__tests__/components/ui/table/DataTable.spec.tsx index 53dee63ece05..f9b5ab30b3c9 100644 --- a/frontend/__tests__/components/ui/table/DataTable.spec.tsx +++ b/frontend/__tests__/components/ui/table/DataTable.spec.tsx @@ -2,9 +2,14 @@ import { render, screen, fireEvent } from "@solidjs/testing-library"; import { createSignal } from "solid-js"; import { describe, it, expect, vi, beforeEach } from "vitest"; -import { DataTable } from "../../../../src/ts/components/ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, +} from "../../../../src/ts/components/ui/table/DataTable"; -const [localStorage, setLocalStorage] = createSignal([]); +const [localStorage, setLocalStorage] = createSignal< + { id: string; desc: boolean }[] +>([]); vi.mock("../../../../src/ts/hooks/useLocalStorage", () => { return { useLocalStorage: () => { @@ -59,6 +64,7 @@ describe("DataTable", () => { sm: true, md: true, }); + setLocalStorage([]); }); it("renders table headers and rows", () => { @@ -157,4 +163,94 @@ describe("DataTable", () => { expect(nameHeader).toHaveClass("sm:hidden"); expect(ageHeader).toHaveClass("hidden sm:table-cell"); }); + + it("updates rows when data changes", async () => { + const [rows, setRows] = createSignal(data); + render(() => ( + + )); + + expect(screen.getAllByRole("row")).toHaveLength(3); + setRows([{ name: "Carol", age: 40 }]); + + expect(await screen.findByText("Carol")).toBeInTheDocument(); + expect(screen.queryByText("Alice")).toBeNull(); + expect(screen.getAllByRole("row")).toHaveLength(2); + }); + + it("updates headers when columns change", async () => { + const [cols, setCols] = createSignal[]>(columns); + render(() => ); + + expect(screen.getByRole("button", { name: "Age" })).toBeInTheDocument(); + + setCols([ + { + id: "age", + accessorKey: "age", + header: "Years", + // oxlint-disable-next-line typescript/no-unsafe-return typescript/no-unsafe-call + cell: (info: any) => info.getValue(), + }, + ]); + + expect( + await screen.findByRole("button", { name: "Years" }), + ).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: "Age" })).toBeNull(); + }); + + it("applies persisted sorting from the initial render", () => { + setLocalStorage([{ id: "age", desc: false }]); + + render(() => ( + + )); + + const rows = screen.getAllByRole("row"); + expect(rows[1]).toHaveTextContent("Bob"); // asc: age 20 first + expect(rows[2]).toHaveTextContent("Alice"); + }); + + it("reports sorting without reordering rows in manual mode", async () => { + const onSortingChange = vi.fn(); + render(() => ( + + )); + + fireEvent.click(screen.getByRole("button", { name: "Age" })); + + expect(onSortingChange).toHaveBeenCalledWith([{ id: "age", desc: true }]); + const rows = screen.getAllByRole("row"); + expect(rows[1]).toHaveTextContent("Alice"); // data order untouched + expect(rows[2]).toHaveTextContent("Bob"); + }); + + it("marks the active row for rowSelection", () => { + const activeRow = (): string | null => "Bob"; + render(() => ( + row.name, + activeRow, + class: "row-selected", + }} + /> + )); + + const bob = screen.getByText("Bob").closest("tr"); + expect(bob).toHaveAttribute("data-state", "selected"); + expect(bob).toHaveClass("row-selected"); + expect(screen.getByText("Alice").closest("tr")).not.toHaveAttribute( + "data-state", + ); + }); }); diff --git a/frontend/package.json b/frontend/package.json index 80bfb6ce964c..8b5a58bf7726 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -44,7 +44,7 @@ "@tanstack/solid-hotkeys": "0.10.0", "@tanstack/solid-query": "5.104.5", "@tanstack/solid-router": "1.170.38", - "@tanstack/solid-table": "8.21.3", + "@tanstack/solid-table": "9.3.1", "@ts-rest/core": "3.52.1", "animejs": "4.2.2", "balloon-css": "1.2.0", diff --git a/frontend/src/ts/components/modals/PbTablesModal.tsx b/frontend/src/ts/components/modals/PbTablesModal.tsx index 02878de8d132..662ee0b7187b 100644 --- a/frontend/src/ts/components/modals/PbTablesModal.tsx +++ b/frontend/src/ts/components/modals/PbTablesModal.tsx @@ -11,7 +11,11 @@ import { Formatting } from "../../utils/format"; import { getLanguageDisplayString } from "../../utils/strings"; import { AnimatedModal } from "../common/AnimatedModal"; import { Fa } from "../common/Fa"; -import { DataTable, DataTableColumnDef } from "../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../ui/table/DataTable"; type PBWithMode2 = PersonalBest & { mode2: Mode2; @@ -52,7 +56,7 @@ function getColumns(options: { format: Formatting; mode: Mode; }): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper().accessor; const { format: f, mode: m } = options; const columns = [ diff --git a/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx b/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx index a62f02bcd258..7932acb0b451 100644 --- a/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx +++ b/frontend/src/ts/components/pages/account-settings/ApeKeysTab.tsx @@ -20,7 +20,11 @@ import { replaceSpacesWithUnderscores } from "../../../utils/strings"; import AsyncContent from "../../common/AsyncContent"; import { Button } from "../../common/Button"; import { Fa } from "../../common/Fa"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; import { Section } from "./utils"; export function ApeKeysTab() { @@ -71,7 +75,8 @@ export function ApeKeysTab() { } function getColumns(): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper() + .accessor; const columns = [ defineColumn("_id", { diff --git a/frontend/src/ts/components/pages/account-settings/BlockedUsersTab.tsx b/frontend/src/ts/components/pages/account-settings/BlockedUsersTab.tsx index 71cf573eba1c..83e7282e4c34 100644 --- a/frontend/src/ts/components/pages/account-settings/BlockedUsersTab.tsx +++ b/frontend/src/ts/components/pages/account-settings/BlockedUsersTab.tsx @@ -11,7 +11,11 @@ import { showSimpleModal } from "../../../states/simple-modal"; import AsyncContent from "../../common/AsyncContent"; import { Button } from "../../common/Button"; import { User } from "../../common/User"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; import { Section } from "./utils"; export function BlockedUsersTab() { @@ -44,7 +48,8 @@ export function BlockedUsersTab() { } function getColumns(): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper() + .accessor; const cols = [ defineColumn("initiatorName", { header: "name", diff --git a/frontend/src/ts/components/pages/account/Table.tsx b/frontend/src/ts/components/pages/account/Table.tsx index 705bfcb38962..19d2e1f5073f 100644 --- a/frontend/src/ts/components/pages/account/Table.tsx +++ b/frontend/src/ts/components/pages/account/Table.tsx @@ -15,7 +15,11 @@ import { Formatting } from "../../../utils/format"; import { replaceUnderscoresWithSpaces } from "../../../utils/strings"; import { Button } from "../../common/Button"; import { Fa, FaProps } from "../../common/Fa"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; import { MiniResultChart } from "./MiniResultChart"; type Sorting = { @@ -93,7 +97,10 @@ function getColumns({ tags: TagItem[]; onMiniResultChartSelected(val: string): void; }): DataTableColumnDef>[] { - const defineColumn = createColumnHelper>().accessor; + const defineColumn = createColumnHelper< + DataTableFeatures, + SnapshotResult + >().accessor; const columns = [ defineColumn("isPb", { header: "", diff --git a/frontend/src/ts/components/pages/connections/FriendsList.tsx b/frontend/src/ts/components/pages/connections/FriendsList.tsx index afaf71c64bd9..74d85747f7a8 100644 --- a/frontend/src/ts/components/pages/connections/FriendsList.tsx +++ b/frontend/src/ts/components/pages/connections/FriendsList.tsx @@ -28,7 +28,11 @@ import { Button } from "../../common/Button"; import { H2 } from "../../common/Headers"; import { LoadingCircle } from "../../common/LoadingCircle"; import { User } from "../../common/User"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; export function FriendsList() { const query = useQuery(() => getFriendsListQuery()); @@ -125,7 +129,7 @@ function getColumns({ }: { format: Formatting; }): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper().accessor; const cols = [ defineColumn("name", { enableSorting: true, diff --git a/frontend/src/ts/components/pages/connections/PendingRequests.tsx b/frontend/src/ts/components/pages/connections/PendingRequests.tsx index 85bbf2224c10..8aec671da2d5 100644 --- a/frontend/src/ts/components/pages/connections/PendingRequests.tsx +++ b/frontend/src/ts/components/pages/connections/PendingRequests.tsx @@ -14,7 +14,11 @@ import AsyncContent from "../../common/AsyncContent"; import { Button } from "../../common/Button"; import { H2 } from "../../common/Headers"; import { User } from "../../common/User"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; export function PendingRequests() { const columns = createMemo(() => getColumns()); @@ -41,7 +45,8 @@ export function PendingRequests() { } function getColumns(): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper() + .accessor; const cols = [ defineColumn("initiatorName", { enableSorting: true, diff --git a/frontend/src/ts/components/pages/leaderboard/Table.tsx b/frontend/src/ts/components/pages/leaderboard/Table.tsx index 4a4cbe40ecc1..d4fbbbfcc330 100644 --- a/frontend/src/ts/components/pages/leaderboard/Table.tsx +++ b/frontend/src/ts/components/pages/leaderboard/Table.tsx @@ -2,7 +2,7 @@ import { LeaderboardEntry, XpLeaderboardEntry, } from "@monkeytype/schemas/leaderboards"; -import { createColumnHelper } from "@tanstack/solid-table"; +import { createColumnHelper, type RowData } from "@tanstack/solid-table"; import { format as dateFormat } from "date-fns/format"; import { formatDistanceToNow } from "date-fns/formatDistanceToNow"; import { Accessor, createMemo, JSXElement, Show } from "solid-js"; @@ -16,7 +16,11 @@ import { Formatting } from "../../../utils/format"; import { abbreviateNumber } from "../../../utils/numbers"; import { Fa } from "../../common/Fa"; import { User } from "../../common/User"; -import { DataTable, DataTableColumnDef } from "../../ui/table/DataTable"; +import { + DataTable, + DataTableColumnDef, + DataTableFeatures, +} from "../../ui/table/DataTable"; type SpeedEntry = LeaderboardEntry; type XpEntry = XpLeaderboardEntry; @@ -117,58 +121,67 @@ function NoEntriesFound(): JSXElement { } const friendsRankColumn = () => - createColumnHelper().accessor("friendsRank", { - header: () => , - cell: (info) => - info.getValue() === 1 ? : info.getValue(), - meta: { - align: "center", - headerMeta: { - "aria-label": "Friends rank", - "data-balloon-pos": "down", + createColumnHelper().accessor( + "friendsRank", + { + header: () => , + cell: (info) => + info.getValue() === 1 ? : info.getValue(), + meta: { + align: "center", + headerMeta: { + "aria-label": "Friends rank", + "data-balloon-pos": "down", + }, }, }, - }); + ); const rankColumn = (friendsOnly: boolean) => - createColumnHelper().accessor("rank", { - header: () => , - cell: (info) => - info.getValue() === 1 ? : info.getValue(), - meta: { - align: "center", - headerMeta: { - "aria-label": "Global rank", - "data-balloon-pos": "down", + createColumnHelper().accessor( + "rank", + { + header: () => , + cell: (info) => + info.getValue() === 1 ? : info.getValue(), + meta: { + align: "center", + headerMeta: { + "aria-label": "Global rank", + "data-balloon-pos": "down", + }, }, }, - }); + ); const userColumn = ({ userOverride, }: { userOverride?: Accessor; }) => - createColumnHelper().accessor("uid", { - header: "name", - cell: (info) => - userOverride?.() ?? ( - - ), - meta: { - cellMeta: () => ({ class: "w-full" }), + createColumnHelper().accessor( + "uid", + { + header: "name", + cell: (info) => + userOverride?.() ?? ( + + ), + meta: { + cellMeta: () => ({ class: "w-full" }), + }, }, - }); + ); -function defineResponsivePair() { +function defineResponsivePair() { return ({ columns, switchBreakpoint: breakpoint, @@ -248,7 +261,8 @@ function getSpeedColumns({ userOverride?: Accessor; addHeader?: boolean; }): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper() + .accessor; const columns = [ friendsRankColumn() as DataTableColumnDef, rankColumn(friendsOnly) as DataTableColumnDef, @@ -329,7 +343,8 @@ function getXpColumns({ userOverride?: Accessor; addHeader?: boolean; }): DataTableColumnDef[] { - const defineColumn = createColumnHelper().accessor; + const defineColumn = createColumnHelper() + .accessor; const columns = [ friendsRankColumn() as DataTableColumnDef, rankColumn(friendsOnly) as DataTableColumnDef, diff --git a/frontend/src/ts/components/ui/table/DataTable.tsx b/frontend/src/ts/components/ui/table/DataTable.tsx index 455f23ba5b2f..9279f13d2fe3 100644 --- a/frontend/src/ts/components/ui/table/DataTable.tsx +++ b/frontend/src/ts/components/ui/table/DataTable.tsx @@ -2,11 +2,15 @@ import { AccessorFnColumnDef, AccessorKeyColumnDef, ColumnDef, - createSolidTable, - flexRender, - getCoreRowModel, - getSortedRowModel, - SortingState, + columnVisibilityFeature, + createSortedRowModel, + createTable, + FlexRender, + rowSelectionFeature, + rowSortingFeature, + tableFeatures, + type RowData, + type SortingState, } from "@tanstack/solid-table"; import { Accessor, @@ -44,13 +48,25 @@ const SortingStateSchema = z.array( }), ); +// Features used by every DataTable; keep the definition static (outside any +// component) so all tables share one features type and one row model factory. +const dataTableFeatures = tableFeatures({ + rowSortingFeature, + rowSelectionFeature, + // getVisibleCells() is feature-gated in v9; v8 always provided it + columnVisibilityFeature, + sortedRowModel: createSortedRowModel(), +}); + +export type DataTableFeatures = typeof dataTableFeatures; + // oxlint-disable-next-line typescript/no-explicit-any -export type DataTableColumnDef = - | ColumnDef - | AccessorFnColumnDef - | AccessorKeyColumnDef; +export type DataTableColumnDef = + | ColumnDef + | AccessorFnColumnDef + | AccessorKeyColumnDef; -export type DataTableProps = { +export type DataTableProps = { id: string; columns: DataTableColumnDef[]; data: TData[]; @@ -76,7 +92,7 @@ export type DataTableProps = { }; // oxlint-disable-next-line typescript/no-explicit-any -export function DataTable( +export function DataTable( props: DataTableProps, ): JSXElement { const [sorting, setSorting] = useLocalStorage({ @@ -131,99 +147,98 @@ export function DataTable( ); // Ensure reactivity: always produce a fresh array reference + // oxlint-disable-next-line typescript/no-misused-spread const data = createMemo(() => props.data.map((it) => ({ ...it }))); - // Recreate the table instance whenever data or columns change - const table = createMemo(() => - createSolidTable({ - data: data(), - get columns() { - return props.columns; - }, - getCoreRowModel: getCoreRowModel(), - onSortingChange: (it) => { - setSorting(it); - props.onSortingChange?.(sorting()); - }, + // A single persistent table instance; data and columns are passed as + // getters so v9's options store stays reactive. + const table = createTable({ + features: dataTableFeatures, + get data() { + return data(); + }, + // oxlint-disable-next-line typescript/no-explicit-any + get columns(): ColumnDef[] { + return props.columns; + }, + onSortingChange: (it) => { + setSorting(it); + props.onSortingChange?.(sorting()); + }, - //oxlint-disable-next-line solid/reactivity - ...(props.onSortingChange - ? { manualSorting: true } - : { getSortedRowModel: getSortedRowModel() }), - enableRowSelection: () => props.rowSelection !== undefined, - getRowId: (row, index) => - props.rowSelection !== undefined - ? props.rowSelection.getRowId(row) - : typeof (row as Record)["_id"] === "string" - ? ((row as Record)["_id"] as string) - : index.toString(), - onRowSelectionChange: setRowSelection, + //oxlint-disable-next-line solid/reactivity + ...(props.onSortingChange ? { manualSorting: true } : {}), + enableRowSelection: () => props.rowSelection !== undefined, + getRowId: (row, index) => + props.rowSelection !== undefined + ? props.rowSelection.getRowId(row) + : typeof (row as Record)["_id"] === "string" + ? ((row as Record)["_id"] as string) + : index.toString(), + onRowSelectionChange: setRowSelection, - state: { - get sorting() { - return sorting(); - }, - get rowSelection() { - return rowSelection(); - }, + state: { + get sorting() { + return sorting(); }, - }), - ); + get rowSelection() { + return rowSelection(); + }, + }, + }); //create column visibility classes once, make them accessible via the column.id const columnVisibility = createMemo(() => { return Object.fromEntries( - table() - .getAllColumns() - .map((it) => { - const breakpoint = - it.columnDef.meta?.breakpoint === "xxl" - ? "2xl" - : it.columnDef.meta?.breakpoint; - const maxBreakpoint = - it.columnDef.meta?.maxBreakpoint === "xxl" - ? "2xl" - : it.columnDef.meta?.maxBreakpoint; + table.getAllColumns().map((it) => { + const breakpoint = + it.columnDef.meta?.breakpoint === "xxl" + ? "2xl" + : it.columnDef.meta?.breakpoint; + const maxBreakpoint = + it.columnDef.meta?.maxBreakpoint === "xxl" + ? "2xl" + : it.columnDef.meta?.maxBreakpoint; - // 🚨 Tailwind does not generate CSS for dynamically constructed class names. - const classes = { - hidden: false, - "xxs:table-cell": false, - "xs:table-cell": false, - "sm:table-cell": false, - "md:table-cell": false, - "lg:table-cell": false, - "xl:table-cell": false, - "2xl:table-cell": false, - "xxs:hidden": false, - "xs:hidden": false, - "sm:hidden": false, - "md:hidden": false, - "lg:hidden": false, - "xl:hidden": false, - "2xl:hidden": false, - }; - if (breakpoint !== undefined) { - classes.hidden = true; - classes[`${breakpoint}:table-cell`] = true; - } - if (maxBreakpoint !== undefined) { - classes[`${maxBreakpoint}:hidden`] = true; - } - return [it.id, classes]; - }), + // 🚨 Tailwind does not generate CSS for dynamically constructed class names. + const classes = { + hidden: false, + "xxs:table-cell": false, + "xs:table-cell": false, + "sm:table-cell": false, + "md:table-cell": false, + "lg:table-cell": false, + "xl:table-cell": false, + "2xl:table-cell": false, + "xxs:hidden": false, + "xs:hidden": false, + "sm:hidden": false, + "md:hidden": false, + "lg:hidden": false, + "xl:hidden": false, + "2xl:hidden": false, + }; + if (breakpoint !== undefined) { + classes.hidden = true; + classes[`${breakpoint}:table-cell`] = true; + } + if (maxBreakpoint !== undefined) { + classes[`${maxBreakpoint}:hidden`] = true; + } + return [it.id, classes]; + }), ); }); return ( - + {(headerGroup) => ( @@ -252,10 +267,7 @@ export function DataTable( {})} > - {flexRender( - header.column.columnDef.header, - header.getContext(), - )} + } @@ -300,10 +312,7 @@ export function DataTable( {})} > - {flexRender( - header.column.columnDef.header, - header.getContext(), - )} + }> @@ -337,7 +346,7 @@ export function DataTable( - + {(row) => { let rowElement: HTMLTableRowElement | undefined; // a recreated table recreates rows with the same id: keep the newest @@ -392,10 +401,7 @@ export function DataTable( cellClass.class, )} > - {flexRender( - cell.column.columnDef.cell, - cell.getContext(), - )} + ); }} @@ -406,13 +412,12 @@ export function DataTable( {props.noDataRow !== undefined && diff --git a/frontend/src/ts/types/tanstack-table.d.ts b/frontend/src/ts/types/tanstack-table.d.ts index 489ab4306276..d0d99b550924 100644 --- a/frontend/src/ts/types/tanstack-table.d.ts +++ b/frontend/src/ts/types/tanstack-table.d.ts @@ -5,7 +5,11 @@ import { BreakpointKey } from "../states/breakpoints"; declare module "@tanstack/solid-table" { //This needs to be an interface // oxlint-disable-next-line typescript/consistent-type-definitions - interface ColumnMeta { + interface ColumnMeta< + in out TFeatures extends TableFeatures, + in out TData extends RowData, + TValue extends CellData = CellData, + > { /** * define minimal breakpoint for the column to be visible. * If not set, the column is always visible diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61afb70361d5..346f3b266f1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -343,8 +343,8 @@ importers: specifier: 1.170.38 version: 1.170.38(solid-js@1.9.13) '@tanstack/solid-table': - specifier: 8.21.3 - version: 8.21.3(solid-js@1.9.13) + specifier: 9.3.1 + version: 9.3.1(solid-js@1.9.13) '@ts-rest/core': specifier: 3.52.1 version: 3.52.1(@types/node@24.9.1)(zod@3.23.8) @@ -677,7 +677,7 @@ importers: version: 7.0.2 vitest: specifier: 4.1.0 - version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0(supports-color@10.2.2))(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(@opentelemetry/api@1.9.1)(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0(supports-color@10.2.2))(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3)) packages/contracts: dependencies: @@ -4771,18 +4771,21 @@ packages: peerDependencies: solid-js: ^1.6.0 - '@tanstack/solid-table@8.21.3': - resolution: {integrity: sha512-PmhfSLBxVKiFs01LtYOYrCRhCyTUjxmb4KlxRQiqcALtip8+DOJeeezQM4RSX/GUS0SMVHyH/dNboCpcO++k2A==} - engines: {node: '>=12'} + '@tanstack/solid-table@9.3.1': + resolution: {integrity: sha512-Y1qyK2R4Y65dUNS/flC9TpAcXx8EuN9eImi+QSmx7AyhyRv1xm7051FkmetCkKcpdK3aKOPxG+P1o4CpWsxoWw==} + engines: {node: '>=20'} peerDependencies: solid-js: '>=1.3' '@tanstack/store@0.11.0': resolution: {integrity: sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==} - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} + '@tanstack/store@0.11.2': + resolution: {integrity: sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==} + + '@tanstack/table-core@9.3.1': + resolution: {integrity: sha512-zQvlxSNi2qGM3L4jh85Z6hqMfdIR5qOfD9KHOU32nuKFJGN0RlJ7UvV1lsPb1fPVhpFYI0VP3jJGxLdLDpTKjQ==} + engines: {node: '>=20'} '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} @@ -16222,14 +16225,19 @@ snapshots: '@tanstack/store': 0.11.0 solid-js: 1.9.13 - '@tanstack/solid-table@8.21.3(solid-js@1.9.13)': + '@tanstack/solid-table@9.3.1(solid-js@1.9.13)': dependencies: - '@tanstack/table-core': 8.21.3 + '@tanstack/store': 0.11.2 + '@tanstack/table-core': 9.3.1 solid-js: 1.9.13 '@tanstack/store@0.11.0': {} - '@tanstack/table-core@8.21.3': {} + '@tanstack/store@0.11.2': {} + + '@tanstack/table-core@9.3.1': + dependencies: + '@tanstack/store': 0.11.2 '@testing-library/dom@10.4.1': dependencies: @@ -16917,14 +16925,6 @@ snapshots: optionalDependencies: vite: 7.3.2(@types/node@24.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.0(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@vitest/spy': 4.1.0 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.0(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.70.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.0 @@ -24489,26 +24489,6 @@ snapshots: tsx: 4.21.0 yaml: 2.8.3 - vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3): - dependencies: - lightningcss: 1.32.0 - picomatch: 4.0.5 - postcss: 8.5.8 - rolldown: 1.0.0-rc.12(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0) - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 24.9.1 - esbuild: 0.25.0 - fsevents: 2.3.3 - jiti: 2.7.0 - sass: 1.98.0 - terser: 5.49.1 - tsx: 4.21.0 - yaml: 2.8.3 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.70.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 @@ -24608,36 +24588,6 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0(supports-color@10.2.2))(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.0 - '@vitest/runner': 4.1.0 - '@vitest/snapshot': 4.1.0 - '@vitest/spy': 4.1.0 - '@vitest/utils': 4.1.0 - es-module-lexer: 2.0.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@types/node': 24.9.1 - happy-dom: 20.8.9 - jsdom: 27.4.0(supports-color@10.2.2) - transitivePeerDependencies: - - msw - vitest@4.1.0(@opentelemetry/api@1.9.1)(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0(supports-color@10.2.2))(vite@8.0.5(@emnapi/core@1.11.0)(@emnapi/runtime@1.11.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.70.0)(terser@5.49.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.0