chore(dependencies): update multiple packages to latest versions (#342)

- Upgraded `@types/react` to `19.1.12` and `@types/react-dom` to `19.1.9` for improved type definitions.
- Bumped `react-i18next` to `^15.7.3` for localization fixes.
- Updated `@manypkg/cli` to `^0.25.1` for dependency management improvements.
- Incremented `@sentry/nextjs` to `^10.8.0` and `stripe` to `^18.5.0` to incorporate recent enhancements.
- Adjusted `ai` to `5.0.28` and `@ai-sdk/openai` to `^2.0.23` for AI-related updates.
- Introduced sorting improvements and code examples in `DataTable` for server-side and client-side capabilities.
This commit is contained in:
Giancarlo Buomprisco
2025-08-29 21:25:36 +07:00
committed by GitHub
parent 9ce150609e
commit caf86ce09b
26 changed files with 1287 additions and 984 deletions

View File

@@ -68,6 +68,101 @@ interface DataTableControls {
enableColumnVisibility: boolean; enableColumnVisibility: boolean;
} }
// Server-side sorting example component
function ServerSideSortingExample({
data,
compact = false,
}: {
data: User[];
compact?: boolean;
}) {
const [sorting, setSorting] = useState<{ id: string; desc: boolean }[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [lastSortAction, setLastSortAction] = useState<string>('');
const handleSortingChange = (newSorting: { id: string; desc: boolean }[]) => {
setSorting(newSorting);
setIsLoading(true);
// Simulate server request
const sortInfo =
newSorting.length > 0
? `${newSorting[0].id} ${newSorting[0].desc ? 'DESC' : 'ASC'}`
: 'No sorting';
setLastSortAction(`Server request would be: ORDER BY ${sortInfo}`);
// Simulate loading delay
setTimeout(() => {
setIsLoading(false);
}, 800);
};
const columns: ColumnDef<User>[] = [
{
accessorKey: 'name',
header: 'Name',
enableSorting: true,
},
{
accessorKey: 'department',
header: 'Department',
enableSorting: true,
},
{
accessorKey: 'salary',
header: 'Salary',
enableSorting: true,
cell: ({ row }) => {
const salary = row.getValue('salary') as number;
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
}).format(salary);
},
},
];
return (
<div className="space-y-3">
{!compact && (
<div className="space-y-2 text-xs">
<div className="flex items-center gap-2">
<span className="font-semibold">Current Sort State:</span>
<code className="rounded bg-slate-100 px-2 py-1 text-xs">
{sorting.length > 0
? `${sorting[0].id}: ${sorting[0].desc ? 'desc' : 'asc'}`
: 'none'}
</code>
{isLoading && (
<span className="animate-pulse text-blue-600"> Loading...</span>
)}
</div>
{lastSortAction && (
<div className="text-xs text-slate-600">🔍 {lastSortAction}</div>
)}
</div>
)}
<div className={compact ? 'h-full' : 'h-64 rounded border'}>
<DataTable
columns={columns}
data={data}
pageSize={data.length}
pageCount={1}
getRowId={(row) => row.id}
manualSorting={true} // This is the key difference!
sorting={sorting}
onSortingChange={handleSortingChange}
sticky={!compact}
className={isLoading ? 'opacity-50' : ''}
/>
</div>
</div>
);
}
export function DataTableStory() { export function DataTableStory() {
const { controls, updateControl } = useStoryControls<DataTableControls>({ const { controls, updateControl } = useStoryControls<DataTableControls>({
dataCount: 50, dataCount: 50,
@@ -291,6 +386,7 @@ export function DataTableStory() {
pageCount={Math.ceil(data.length / controls.pageSize)} pageCount={Math.ceil(data.length / controls.pageSize)}
sticky={controls.stickyHeader} sticky={controls.stickyHeader}
forcePagination={true} forcePagination={true}
manualSorting={false} // Enable client-side sorting for demo
columnVisibility={ columnVisibility={
controls.enableColumnVisibility controls.enableColumnVisibility
? columnManagement.columnVisibility ? columnManagement.columnVisibility
@@ -1397,6 +1493,154 @@ export function DataTableStory() {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card>
<CardHeader>
<CardTitle>Server-Side Sorting (Manual Sorting)</CardTitle>
<CardDescription>
Demonstrates server-side sorting with manualSorting=true. Click
headers to see sorting state, but data doesn't change (would
require server integration).
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="rounded-lg border border-blue-200 bg-blue-50 p-3">
<p className="text-sm text-blue-800">
<strong>Server-Side Mode:</strong> This table has
manualSorting=true (default). Clicking column headers triggers
onSortingChange callback where you would fetch sorted data
from your server. The table shows current sort state but
doesn't modify data locally.
</p>
</div>
<ServerSideSortingExample data={data.slice(0, 10)} />
<div className="text-muted-foreground space-y-2 text-xs">
<p>💡 Server-side sorting pattern:</p>
<ul className="ml-4 list-disc space-y-1">
<li>
Use onSortingChange to detect sort column/direction changes
</li>
<li>Send sorting parameters to your API endpoint</li>
<li>Update data state with sorted results from server</li>
<li>Show loading states during sort operations</li>
<li>
Handle sort state in URL for bookmarkable sorted views
</li>
</ul>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Client-Side vs Server-Side Sorting Comparison</CardTitle>
<CardDescription>
Side-by-side comparison of client-side and server-side sorting
approaches
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-6">
<div className="grid gap-4 md:grid-cols-2">
<div className="space-y-3">
<h4 className="text-sm font-semibold text-green-700">
Client-Side Sorting (manualSorting=false)
</h4>
<div className="h-48 rounded border">
<DataTable
columns={[
{
accessorKey: 'name',
header: 'Name',
enableSorting: true,
},
{
accessorKey: 'department',
header: 'Department',
enableSorting: true,
},
{
accessorKey: 'salary',
header: 'Salary',
enableSorting: true,
cell: ({ row }) => {
const salary = row.getValue('salary') as number;
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
}).format(salary);
},
},
]}
data={data.slice(0, 8)}
pageSize={8}
pageCount={1}
getRowId={(row) => row.id}
manualSorting={false}
sticky={true}
/>
</div>
<p className="text-xs text-green-600">
✅ Data sorts immediately when headers are clicked
</p>
</div>
<div className="space-y-3">
<h4 className="text-sm font-semibold text-blue-700">
Server-Side Sorting (manualSorting=true - default)
</h4>
<div className="h-48 rounded border">
<ServerSideSortingExample
data={data.slice(0, 8)}
compact={true}
/>
</div>
<p className="text-xs text-blue-600">
Headers show sort state but data unchanged (awaits
server)
</p>
</div>
</div>
<div className="rounded-lg border bg-slate-50 p-4">
<h4 className="mb-3 text-sm font-semibold">
When to use each approach:
</h4>
<div className="grid gap-4 text-xs md:grid-cols-2">
<div>
<h5 className="mb-2 font-semibold text-green-700">
Client-Side (manualSorting=false)
</h5>
<ul className="ml-4 list-disc space-y-1">
<li>Small to medium datasets (&lt;1000 rows)</li>
<li>All data already loaded</li>
<li>Instant sorting feedback</li>
<li>Works offline</li>
<li>Simpler implementation</li>
</ul>
</div>
<div>
<h5 className="mb-2 font-semibold text-blue-700">
Server-Side (manualSorting=true - default)
</h5>
<ul className="ml-4 list-disc space-y-1">
<li>Large datasets (&gt;1000 rows)</li>
<li>Paginated data loading</li>
<li>Database-level sorting performance</li>
<li>Memory efficient</li>
<li>Required for real-world applications</li>
</ul>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</div> </div>
); );
}; };

View File

@@ -8,11 +8,11 @@
"format": "prettier --check --write \"**/*.{js,cjs,mjs,ts,tsx,md,json}\"" "format": "prettier --check --write \"**/*.{js,cjs,mjs,ts,tsx,md,json}\""
}, },
"dependencies": { "dependencies": {
"@ai-sdk/openai": "^2.0.22", "@ai-sdk/openai": "^2.0.23",
"@faker-js/faker": "^10.0.0", "@faker-js/faker": "^10.0.0",
"@hookform/resolvers": "^5.2.1", "@hookform/resolvers": "^5.2.1",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"ai": "5.0.26", "ai": "5.0.28",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"next": "15.5.2", "next": "15.5.2",
"nodemailer": "^7.0.5", "nodemailer": "^7.0.5",
@@ -30,9 +30,9 @@
"@tailwindcss/postcss": "^4.1.12", "@tailwindcss/postcss": "^4.1.12",
"@types/node": "^24.3.0", "@types/node": "^24.3.0",
"@types/nodemailer": "7.0.1", "@types/nodemailer": "7.0.1",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"babel-plugin-react-compiler": "19.1.0-rc.2", "babel-plugin-react-compiler": "19.1.0-rc.3",
"pino-pretty": "13.0.0", "pino-pretty": "13.0.0",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"recharts": "2.15.3", "recharts": "2.15.3",

View File

@@ -67,7 +67,7 @@
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"recharts": "2.15.3", "recharts": "2.15.3",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"zod": "^3.25.74" "zod": "^3.25.74"
@@ -79,9 +79,9 @@
"@next/bundle-analyzer": "15.5.2", "@next/bundle-analyzer": "15.5.2",
"@tailwindcss/postcss": "^4.1.12", "@tailwindcss/postcss": "^4.1.12",
"@types/node": "^24.3.0", "@types/node": "^24.3.0",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"babel-plugin-react-compiler": "19.1.0-rc.2", "babel-plugin-react-compiler": "19.1.0-rc.3",
"cssnano": "^7.1.1", "cssnano": "^7.1.1",
"pino-pretty": "13.0.0", "pino-pretty": "13.0.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",

View File

@@ -45,7 +45,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@manypkg/cli": "^0.25.0", "@manypkg/cli": "^0.25.1",
"@turbo/gen": "^2.5.6", "@turbo/gen": "^2.5.6",
"cross-env": "^10.0.0", "cross-env": "^10.0.0",
"prettier": "^3.6.2", "prettier": "^3.6.2",

View File

@@ -27,13 +27,13 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },
"typesVersions": { "typesVersions": {

View File

@@ -24,7 +24,7 @@
"@kit/supabase": "workspace:*", "@kit/supabase": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",
"zod": "^3.25.74" "zod": "^3.25.74"

View File

@@ -17,7 +17,7 @@
"dependencies": { "dependencies": {
"@stripe/react-stripe-js": "^3.9.2", "@stripe/react-stripe-js": "^3.9.2",
"@stripe/stripe-js": "^7.9.0", "@stripe/stripe-js": "^7.9.0",
"stripe": "^18.4.0" "stripe": "^18.5.0"
}, },
"devDependencies": { "devDependencies": {
"@kit/billing": "workspace:*", "@kit/billing": "workspace:*",
@@ -27,7 +27,7 @@
"@kit/supabase": "workspace:*", "@kit/supabase": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",

View File

@@ -2,7 +2,7 @@ import 'server-only';
import { StripeServerEnvSchema } from '../schema/stripe-server-env.schema'; import { StripeServerEnvSchema } from '../schema/stripe-server-env.schema';
const STRIPE_API_VERSION = '2025-07-30.basil'; const STRIPE_API_VERSION = '2025-08-27.basil';
/** /**
* @description returns a Stripe instance * @description returns a Stripe instance

View File

@@ -27,7 +27,7 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/node": "^24.3.0", "@types/node": "^24.3.0",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"react": "19.1.1", "react": "19.1.1",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },

View File

@@ -21,7 +21,7 @@
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@types/node": "^24.3.0", "@types/node": "^24.3.0",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"wp-types": "^4.68.1" "wp-types": "^4.68.1"
}, },
"typesVersions": { "typesVersions": {

View File

@@ -36,15 +36,15 @@
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"next": "15.5.2", "next": "15.5.2",
"next-themes": "0.4.6", "next-themes": "0.4.6",
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },
"prettier": "@kit/prettier-config", "prettier": "@kit/prettier-config",

View File

@@ -23,7 +23,7 @@
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",

View File

@@ -31,11 +31,11 @@
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"next": "15.5.2", "next": "15.5.2",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },

View File

@@ -21,11 +21,11 @@
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-i18next": "^15.7.2" "react-i18next": "^15.7.3"
}, },
"prettier": "@kit/prettier-config", "prettier": "@kit/prettier-config",
"typesVersions": { "typesVersions": {

View File

@@ -35,8 +35,8 @@
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"lucide-react": "^0.542.0", "lucide-react": "^0.542.0",
@@ -44,7 +44,7 @@
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },
"prettier": "@kit/prettier-config", "prettier": "@kit/prettier-config",

View File

@@ -24,7 +24,7 @@
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-i18next": "^15.7.2" "react-i18next": "^15.7.3"
}, },
"dependencies": { "dependencies": {
"i18next": "25.4.2", "i18next": "25.4.2",

View File

@@ -24,7 +24,7 @@
"@kit/sentry": "workspace:*", "@kit/sentry": "workspace:*",
"@kit/shared": "workspace:*", "@kit/shared": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"react": "19.1.1", "react": "19.1.1",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },

View File

@@ -24,7 +24,7 @@
"@kit/eslint-config": "workspace:*", "@kit/eslint-config": "workspace:*",
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"react": "19.1.1", "react": "19.1.1",
"zod": "^3.25.74" "zod": "^3.25.74"
}, },

View File

@@ -17,7 +17,7 @@
"@kit/eslint-config": "workspace:*", "@kit/eslint-config": "workspace:*",
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"react": "19.1.1" "react": "19.1.1"
}, },
"typesVersions": { "typesVersions": {

View File

@@ -16,7 +16,7 @@
"./config/server": "./src/sentry.client.server.ts" "./config/server": "./src/sentry.client.server.ts"
}, },
"dependencies": { "dependencies": {
"@sentry/nextjs": "^10.6.0", "@sentry/nextjs": "^10.8.0",
"import-in-the-middle": "1.14.2" "import-in-the-middle": "1.14.2"
}, },
"devDependencies": { "devDependencies": {
@@ -24,7 +24,7 @@
"@kit/monitoring-core": "workspace:*", "@kit/monitoring-core": "workspace:*",
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"react": "19.1.1" "react": "19.1.1"
}, },
"typesVersions": { "typesVersions": {

View File

@@ -26,8 +26,8 @@
"@kit/ui": "workspace:*", "@kit/ui": "workspace:*",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"react": "19.1.1", "react": "19.1.1",
"react-dom": "19.1.1", "react-dom": "19.1.1",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",

View File

@@ -20,7 +20,7 @@
"@kit/eslint-config": "workspace:*", "@kit/eslint-config": "workspace:*",
"@kit/prettier-config": "workspace:*", "@kit/prettier-config": "workspace:*",
"@kit/tsconfig": "workspace:*", "@kit/tsconfig": "workspace:*",
"@types/react": "19.1.11" "@types/react": "19.1.12"
}, },
"dependencies": { "dependencies": {
"pino": "^9.8.0" "pino": "^9.8.0"

View File

@@ -28,7 +28,7 @@
"@supabase/ssr": "^0.7.0", "@supabase/ssr": "^0.7.0",
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"next": "15.5.2", "next": "15.5.2",
"react": "19.1.1", "react": "19.1.1",
"server-only": "^0.0.1", "server-only": "^0.0.1",

View File

@@ -28,8 +28,8 @@
"@supabase/supabase-js": "2.55.0", "@supabase/supabase-js": "2.55.0",
"@tanstack/react-query": "5.85.5", "@tanstack/react-query": "5.85.5",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
"@types/react": "19.1.11", "@types/react": "19.1.12",
"@types/react-dom": "19.1.8", "@types/react-dom": "19.1.9",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"eslint": "^9.34.0", "eslint": "^9.34.0",
@@ -38,7 +38,7 @@
"prettier": "^3.6.2", "prettier": "^3.6.2",
"react-day-picker": "^9.9.0", "react-day-picker": "^9.9.0",
"react-hook-form": "^7.62.0", "react-hook-form": "^7.62.0",
"react-i18next": "^15.7.2", "react-i18next": "^15.7.3",
"sonner": "^2.0.7", "sonner": "^2.0.7",
"tailwindcss": "4.1.12", "tailwindcss": "4.1.12",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",

View File

@@ -8,6 +8,7 @@ import {
Cell, Cell,
flexRender, flexRender,
getCoreRowModel, getCoreRowModel,
getSortedRowModel,
useReactTable, useReactTable,
} from '@tanstack/react-table'; } from '@tanstack/react-table';
import type { import type {
@@ -21,8 +22,10 @@ import type {
VisibilityState, VisibilityState,
} from '@tanstack/react-table'; } from '@tanstack/react-table';
import { import {
ChevronDown,
ChevronLeft, ChevronLeft,
ChevronRight, ChevronRight,
ChevronUp,
ChevronsLeft, ChevronsLeft,
ChevronsRight, ChevronsRight,
} from 'lucide-react'; } from 'lucide-react';
@@ -87,6 +90,7 @@ interface ReactTableProps<T extends DataItem> {
}) => (props: React.PropsWithChildren<object>) => React.ReactNode; }) => (props: React.PropsWithChildren<object>) => React.ReactNode;
noResultsMessage?: React.ReactNode; noResultsMessage?: React.ReactNode;
forcePagination?: boolean; // Force pagination to show even when pageCount <= 1 forcePagination?: boolean; // Force pagination to show even when pageCount <= 1
manualSorting?: boolean; // Default true for server-side sorting, set false for client-side sorting
} }
export function DataTable<RecordData extends DataItem>({ export function DataTable<RecordData extends DataItem>({
@@ -115,6 +119,7 @@ export function DataTable<RecordData extends DataItem>({
rowSelection: controlledRowSelection, rowSelection: controlledRowSelection,
sticky = false, sticky = false,
forcePagination = false, forcePagination = false,
manualSorting = true,
}: ReactTableProps<RecordData>) { }: ReactTableProps<RecordData>) {
// TODO: remove when https://github.com/TanStack/table/issues/5567 gets fixed // TODO: remove when https://github.com/TanStack/table/issues/5567 gets fixed
'use no memo'; 'use no memo';
@@ -149,10 +154,11 @@ export function DataTable<RecordData extends DataItem>({
getRowId, getRowId,
columns, columns,
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
enableColumnPinning: true, enableColumnPinning: true,
enableRowSelection: true, enableRowSelection: true,
manualPagination: true, manualPagination: true,
manualSorting: true, manualSorting,
onColumnFiltersChange: setColumnFilters, onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: (updater) => { onColumnVisibilityChange: (updater) => {
if (typeof updater === 'function') { if (typeof updater === 'function') {
@@ -350,12 +356,42 @@ export function DataTable<RecordData extends DataItem>({
}} }}
key={header.id} key={header.id}
> >
{header.isPlaceholder {header.isPlaceholder ? null : (
? null <div
: flexRender( className={cn(
'flex items-center gap-2',
header.column.getCanSort()
? 'hover:bg-accent/50 -mx-3 cursor-pointer rounded px-3 py-1 select-none'
: '',
)}
onClick={header.column.getToggleSortingHandler()}
>
{flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext(), header.getContext(),
)} )}
{header.column.getCanSort() && (
<div className="flex flex-col">
<ChevronUp
className={cn(
'h-3 w-3',
header.column.getIsSorted() === 'asc'
? 'text-foreground'
: 'text-muted-foreground/50',
)}
/>
<ChevronDown
className={cn(
'-mt-1 h-3 w-3',
header.column.getIsSorted() === 'desc'
? 'text-foreground'
: 'text-muted-foreground/50',
)}
/>
</div>
)}
</div>
)}
</TableHead> </TableHead>
); );
})} })}

1899
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff