diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index e3710503c..1d2584b46 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -32,6 +32,10 @@ jobs:
- name: Type-check test-app
run: cd packages/${{ matrix.adapter == 'vue' && 'vue3' || matrix.adapter }}/test-app && pnpm run type-check
+ - name: ESLint test-app
+ run: cd packages/${{ matrix.adapter == 'vue' && 'vue3' || matrix.adapter }}/test-app && pnpm run lint
+ if: matrix.adapter == 'react'
+
- name: Install Playwright Browsers
run: pnpm playwright install chromium
diff --git a/package.json b/package.json
index 0d89b3fee..76e606851 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"dev:test-app:svelte": "pnpx concurrently -c \"#c4b5fd,#ffa800\" \"cd tests/app && PACKAGE=svelte pnpm serve:watch\" \"cd packages/svelte/test-app && pnpm run dev\" --names=server,vite",
"dev:test-app:vue": "pnpx concurrently -c \"#c4b5fd,#ffa800\" \"cd tests/app && PACKAGE=vue3 pnpm serve:watch\" \"cd packages/vue3/test-app && pnpm run dev\" --names=server,vite",
"es2020-check": "pnpm -r --filter './packages/*' es2020-check",
+ "lint:test-app:react": "cd packages/react/test-app && pnpm run lint",
"type-check:test-app": "pnpm -r --filter './packages/*/test-app' type-check",
"type-check:test-app:react": "cd packages/react/test-app && pnpm run type-check",
"type-check:test-app:svelte": "cd packages/svelte/test-app && pnpm run type-check",
@@ -28,13 +29,13 @@
"format": "prettier --write ."
},
"dependencies": {
- "@playwright/test": "^1.55.1",
+ "@playwright/test": "^1.56.0",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.3.0",
"prettier-plugin-svelte": "^3.4.0",
"prettier-plugin-tailwindcss": "^0.6.14"
},
"optionalDependencies": {
- "@rollup/rollup-linux-x64-gnu": "^4.52.2"
+ "@rollup/rollup-linux-x64-gnu": "^4.52.4"
}
}
diff --git a/packages/react/test-app/Layouts/NestedLayout.tsx b/packages/react/test-app/Layouts/NestedLayout.tsx
index ce99e1d9a..3bcf8654c 100644
--- a/packages/react/test-app/Layouts/NestedLayout.tsx
+++ b/packages/react/test-app/Layouts/NestedLayout.tsx
@@ -2,7 +2,7 @@ import { usePage } from '@inertiajs/react'
import { useId, useState } from 'react'
export default ({ children }: { children: React.ReactNode }) => {
- const [createdAt, setCreatedAt] = useState(Date.now())
+ const [createdAt] = useState(Date.now())
window._inertia_nested_layout_id = useId()
window._inertia_nested_layout_props = usePage().props
diff --git a/packages/react/test-app/Layouts/SiteLayout.tsx b/packages/react/test-app/Layouts/SiteLayout.tsx
index 04cd640d7..8f0e381bd 100644
--- a/packages/react/test-app/Layouts/SiteLayout.tsx
+++ b/packages/react/test-app/Layouts/SiteLayout.tsx
@@ -2,7 +2,7 @@ import { usePage } from '@inertiajs/react'
import { useId, useState } from 'react'
export default ({ children }: { children: React.ReactNode }) => {
- const [createdAt, setCreatedAt] = useState(Date.now())
+ const [createdAt] = useState(Date.now())
window._inertia_layout_id = useId()
window._inertia_site_layout_props = usePage().props
diff --git a/packages/react/test-app/Pages/DeepMergeProps.tsx b/packages/react/test-app/Pages/DeepMergeProps.tsx
index 4c8ce6fa6..e6dad4f79 100644
--- a/packages/react/test-app/Pages/DeepMergeProps.tsx
+++ b/packages/react/test-app/Pages/DeepMergeProps.tsx
@@ -1,15 +1,13 @@
import { router } from '@inertiajs/react'
import { useState } from 'react'
-export default ({
- bar,
- foo,
- baz,
-}: {
+type PageProps = {
bar: number[]
foo: { page: number; data: number[]; per_page: number; meta: { label: string } }
baz: number[]
-}) => {
+}
+
+export default ({ bar, foo, baz }: PageProps) => {
const [page, setPage] = useState(foo.page)
const reloadIt = () => {
@@ -19,7 +17,7 @@ export default ({
},
only: ['foo', 'baz'],
onSuccess(visit) {
- setPage((visit.props as any).foo.page)
+ setPage((visit.props as unknown as PageProps).foo.page)
},
})
}
diff --git a/packages/react/test-app/Pages/Dump.tsx b/packages/react/test-app/Pages/Dump.tsx
index ad606a4b0..3728f8a72 100644
--- a/packages/react/test-app/Pages/Dump.tsx
+++ b/packages/react/test-app/Pages/Dump.tsx
@@ -1,6 +1,6 @@
import type { Method } from '@inertiajs/core'
import { usePage } from '@inertiajs/react'
-import { useEffect } from 'react'
+import { useEffect, useMemo } from 'react'
import type { MulterFile } from '../types'
export default ({
@@ -20,19 +20,22 @@ export default ({
}) => {
const page = usePage()
- const dump = {
- headers,
- method,
- form,
- files: files ? files : {},
- query,
- url,
- $page: page,
- }
+ const dump = useMemo(
+ () => ({
+ headers,
+ method,
+ form,
+ files: files ? files : {},
+ query,
+ url,
+ $page: page,
+ }),
+ [headers, method, form, files, query, url, page],
+ )
useEffect(() => {
window._inertia_request_dump = dump
- }, [])
+ }, [dump])
return (
diff --git a/packages/react/test-app/Pages/Events.tsx b/packages/react/test-app/Pages/Events.tsx
index 6ae27ec83..724e0925d 100644
--- a/packages/react/test-app/Pages/Events.tsx
+++ b/packages/react/test-app/Pages/Events.tsx
@@ -2,7 +2,7 @@ import { Link, router, usePage } from '@inertiajs/react'
declare global {
interface Window {
- messages: string[]
+ messages: unknown[]
}
}
@@ -15,7 +15,7 @@ export default () => {
const page = usePage()
- const internalAlert = (...args: any[]) => {
+ const internalAlert = (...args: unknown[]) => {
args.forEach((arg) => window.messages.push(arg))
}
@@ -87,7 +87,7 @@ export default () => {
const beforeVisitPreventGlobalInertia = (e: React.MouseEvent) => {
e.preventDefault()
document.addEventListener('inertia:before', () => internalAlert('addEventListener(inertia:before)'))
- router.on('before', (visit) => {
+ router.on('before', () => {
internalAlert('Inertia.on(before)')
return false
})
@@ -502,7 +502,7 @@ export default () => {
{
+ onBefore={() => {
internalAlert('linkOnBefore')
return false
}}
diff --git a/packages/react/test-app/Pages/FormComponent/Reset.tsx b/packages/react/test-app/Pages/FormComponent/Reset.tsx
index 8e103bcc9..c3702266d 100644
--- a/packages/react/test-app/Pages/FormComponent/Reset.tsx
+++ b/packages/react/test-app/Pages/FormComponent/Reset.tsx
@@ -1,3 +1,4 @@
+import { FormComponentRef } from '@inertiajs/core'
import { Form } from '@inertiajs/react'
import { useRef } from 'react'
@@ -8,11 +9,10 @@ declare global {
}
export default function Reset() {
- const formRef = useRef(null)
+ const formRef = useRef
(null)
// Expose reset function to window for testing
window.resetForm = (...fields: string[]) => {
- // @ts-expect-error
formRef.current?.reset(...fields)
}
diff --git a/packages/react/test-app/Pages/FormHelper/Data.tsx b/packages/react/test-app/Pages/FormHelper/Data.tsx
index a0306eaa1..688b86611 100644
--- a/packages/react/test-app/Pages/FormHelper/Data.tsx
+++ b/packages/react/test-app/Pages/FormHelper/Data.tsx
@@ -1,6 +1,6 @@
import { useForm, usePage } from '@inertiajs/react'
-export default ({ errors }: { errors?: { name?: string; handle?: string } }) => {
+export default () => {
const form = useForm({
name: 'foo',
handle: 'example',
diff --git a/packages/react/test-app/Pages/FormHelper/EffectCount.tsx b/packages/react/test-app/Pages/FormHelper/EffectCount.tsx
index 2efb35019..06d0cadb3 100644
--- a/packages/react/test-app/Pages/FormHelper/EffectCount.tsx
+++ b/packages/react/test-app/Pages/FormHelper/EffectCount.tsx
@@ -9,7 +9,7 @@ export default () => {
useEffect(() => {
setData('count', count)
setDefaults()
- setEffectCount(effectCount + 1)
+ setEffectCount((e) => e + 1)
}, [count, setData, setDefaults])
return (
diff --git a/packages/react/test-app/Pages/FormHelper/Errors.tsx b/packages/react/test-app/Pages/FormHelper/Errors.tsx
index c67643f3d..9aba8b624 100644
--- a/packages/react/test-app/Pages/FormHelper/Errors.tsx
+++ b/packages/react/test-app/Pages/FormHelper/Errors.tsx
@@ -1,6 +1,6 @@
import { useForm } from '@inertiajs/react'
-export default ({ errors }: { errors?: { name?: string; handle?: string } }) => {
+export default () => {
const form = useForm({ name: 'foo', handle: 'example', remember: false })
const submit = () => {
diff --git a/packages/react/test-app/Pages/FormHelper/Events.tsx b/packages/react/test-app/Pages/FormHelper/Events.tsx
index 281176426..f7d0076da 100644
--- a/packages/react/test-app/Pages/FormHelper/Events.tsx
+++ b/packages/react/test-app/Pages/FormHelper/Events.tsx
@@ -1,6 +1,6 @@
import type { Errors, Page, PendingVisit } from '@inertiajs/core'
import { useForm, usePage } from '@inertiajs/react'
-import type { CancelTokenSource } from 'axios'
+import type { AxiosProgressEvent, CancelTokenSource } from 'axios'
import { useEffect } from 'react'
declare global {
@@ -39,7 +39,7 @@ const callbacks = (overrides = {}) => ({
...overrides,
})
-export default ({ errors }: { errors?: { name?: string; handle?: string } }) => {
+export default () => {
const form = useForm({ name: 'foo', remember: false })
const page = usePage()
@@ -95,7 +95,7 @@ export default ({ errors }: { errors?: { name?: string; handle?: string } }) =>
const onBeforeVisitCancelled = () => {
form.post('/sleep', {
...callbacks({
- onBefore: (visit: PendingVisit) => {
+ onBefore: () => {
pushEvent('onBefore')
return false
},
@@ -121,7 +121,7 @@ export default ({ errors }: { errors?: { name?: string; handle?: string } }) =>
form.post('/dump/post', {
...callbacks({
- onProgress: (event: any) => {
+ onProgress: (event: AxiosProgressEvent) => {
pushEvent('onProgress')
pushData('progressEvent', event)
},
@@ -157,7 +157,7 @@ export default ({ errors }: { errors?: { name?: string; handle?: string } }) =>
const onSuccessPromiseVisit = () => {
form.post('/dump/post', {
...callbacks({
- onSuccess: (page: Page) => {
+ onSuccess: () => {
pushEvent('onSuccess')
setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)
return new Promise((resolve) => setTimeout(resolve, 20))
@@ -180,7 +180,7 @@ export default ({ errors }: { errors?: { name?: string; handle?: string } }) =>
const onErrorPromiseVisit = () => {
form.post('/form-helper/events/errors', {
...callbacks({
- onError: (errors: Errors) => {
+ onError: () => {
pushEvent('onError')
setTimeout(() => pushEvent('onFinish should have been fired by now if Promise functionality did not work'), 5)
return new Promise((resolve) => setTimeout(resolve, 20))
@@ -196,7 +196,7 @@ export default ({ errors }: { errors?: { name?: string; handle?: string } }) =>
const onSuccessResetValue = () => {
form.post(page.url, {
...callbacks({
- onSuccess: (page: Page) => {
+ onSuccess: () => {
form.reset()
},
}),
diff --git a/packages/react/test-app/Pages/FormHelper/TypeScript/DynamicInputName.tsx b/packages/react/test-app/Pages/FormHelper/TypeScript/DynamicInputName.tsx
index acc2681ec..0f3994d70 100644
--- a/packages/react/test-app/Pages/FormHelper/TypeScript/DynamicInputName.tsx
+++ b/packages/react/test-app/Pages/FormHelper/TypeScript/DynamicInputName.tsx
@@ -3,7 +3,7 @@ import { useForm } from '@inertiajs/react'
interface ClientForm {
name: string
- [key: string]: any
+ [key: string]: any // eslint-disable-line @typescript-eslint/no-explicit-any
}
export default function DynamicInputName() {
diff --git a/packages/react/test-app/Pages/FormHelper/TypeScript/Errors.tsx b/packages/react/test-app/Pages/FormHelper/TypeScript/Errors.tsx
index 3afd7410d..ec33db96c 100644
--- a/packages/react/test-app/Pages/FormHelper/TypeScript/Errors.tsx
+++ b/packages/react/test-app/Pages/FormHelper/TypeScript/Errors.tsx
@@ -17,8 +17,8 @@ export default function Errors() {
const form = useForm(defaultData)
// Get Errors
- form.errors.name
- form.errors['company.name']
+ console.log(form.errors.name)
+ console.log(form.errors['company.name'])
// Clear Errors
form.clearErrors('name')
@@ -53,9 +53,9 @@ export default function Errors() {
form.setError({ 'users.0.name': 'Validation error' })
// @ts-expect-error - Form has no email field
- form.errors.email
+ console.log(form.errors.email)
// @ts-expect-error - Company has no email field
- form.errors['company.email']
+ console.log(form.errors['company.email'])
// @ts-expect-error - Form has no email field
form.clearErrors('email')
@@ -83,6 +83,4 @@ export default function Errors() {
form.setError('users.0.email', 'Validation error')
// @ts-expect-error - A user has no email field
form.setError({ 'users.0.email': 'Validation error' })
-
- return null
}
diff --git a/packages/react/test-app/Pages/FormHelper/TypeScript/Generic.tsx b/packages/react/test-app/Pages/FormHelper/TypeScript/Generic.tsx
index 59c5c5591..3a183d073 100644
--- a/packages/react/test-app/Pages/FormHelper/TypeScript/Generic.tsx
+++ b/packages/react/test-app/Pages/FormHelper/TypeScript/Generic.tsx
@@ -9,5 +9,6 @@ interface GenericProps> {
export default function Generic>({
form,
}: GenericProps) {
+ console.log(form)
return {/* Generic form component */}
}
diff --git a/packages/react/test-app/Pages/FormHelper/TypeScript/ValidationKey.tsx b/packages/react/test-app/Pages/FormHelper/TypeScript/ValidationKey.tsx
index 2e38e9afb..0ff12fbd4 100644
--- a/packages/react/test-app/Pages/FormHelper/TypeScript/ValidationKey.tsx
+++ b/packages/react/test-app/Pages/FormHelper/TypeScript/ValidationKey.tsx
@@ -21,5 +21,7 @@ const validation = >(errors: () =>
}
export default function ValidationKey() {
+ validation(() => ({ name: 'Validation error' }))
+
return {/* ValidationKey component */}
}
diff --git a/packages/react/test-app/Pages/Head.tsx b/packages/react/test-app/Pages/Head.tsx
index b9b28a74f..20ce0952f 100644
--- a/packages/react/test-app/Pages/Head.tsx
+++ b/packages/react/test-app/Pages/Head.tsx
@@ -8,14 +8,14 @@ export default () => {
{/* @ts-expect-error - The content attribute must be a string, we support passing other types for backwards compatibility */}
- {/* @ts-expect-error */}
+ {/* @ts-expect-error - same as above */}
- {/* @ts-expect-error */}
+ {/* @ts-expect-error - same as above */}
- {/* @ts-expect-error */}
+ {/* @ts-expect-error - same as above */}
- {/* @ts-expect-error */}
+ {/* @ts-expect-error - same as above */}
diff --git a/packages/react/test-app/Pages/InfiniteScroll/Filtering.tsx b/packages/react/test-app/Pages/InfiniteScroll/Filtering.tsx
index b419c3eab..35bc84800 100644
--- a/packages/react/test-app/Pages/InfiniteScroll/Filtering.tsx
+++ b/packages/react/test-app/Pages/InfiniteScroll/Filtering.tsx
@@ -1,6 +1,6 @@
import { InfiniteScroll, Link, useForm } from '@inertiajs/react'
import { debounce } from 'lodash-es'
-import { useCallback, useEffect } from 'react'
+import { useEffect, useMemo } from 'react'
import UserCard, { User } from './UserCard'
interface Props {
@@ -17,23 +17,24 @@ export default ({ users, preserveState, filter, search }: Props) => {
search: search,
})
- const debouncedSearch = useCallback(
- debounce(() => {
- get(
- '',
- preserveState
- ? {
- preserveState: true,
- replace: true,
- only: ['users', 'search', 'filter'],
- reset: ['users'],
- }
- : {
- replace: true,
- },
- )
- }, 250),
- [get],
+ const debouncedSearch = useMemo(
+ () =>
+ debounce(() => {
+ get(
+ '',
+ preserveState
+ ? {
+ preserveState: true,
+ replace: true,
+ only: ['users', 'search', 'filter'],
+ reset: ['users'],
+ }
+ : {
+ replace: true,
+ },
+ )
+ }, 250),
+ [get, preserveState],
)
useEffect(() => {
diff --git a/packages/react/test-app/Pages/InfiniteScroll/Grid.tsx b/packages/react/test-app/Pages/InfiniteScroll/Grid.tsx
index ef8ddf20c..387083424 100644
--- a/packages/react/test-app/Pages/InfiniteScroll/Grid.tsx
+++ b/packages/react/test-app/Pages/InfiniteScroll/Grid.tsx
@@ -10,7 +10,7 @@ export default ({ users }: { users: { data: User[] } }) => {
Loading more users...
)}
>
- {({ loading, loadingPrevious, loadingNext }) => users.data.map((user) => )}
+ {() => users.data.map((user) => )}
)
}
diff --git a/packages/react/test-app/Pages/InfiniteScroll/ProgrammaticRef.tsx b/packages/react/test-app/Pages/InfiniteScroll/ProgrammaticRef.tsx
index 8b8edda88..5e0578639 100644
--- a/packages/react/test-app/Pages/InfiniteScroll/ProgrammaticRef.tsx
+++ b/packages/react/test-app/Pages/InfiniteScroll/ProgrammaticRef.tsx
@@ -1,6 +1,6 @@
import { InfiniteScrollRef } from '@inertiajs/core'
import { InfiniteScroll } from '@inertiajs/react'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import UserCard, { User } from './UserCard'
export default ({ users }: { users: { data: User[] } }) => {
@@ -8,10 +8,10 @@ export default ({ users }: { users: { data: User[] } }) => {
const [hasPrevious, setHasMoreBefore] = useState(false)
const [hasNext, setHasMoreAfter] = useState(false)
- const updateStates = () => {
+ const updateStates = useCallback(() => {
setHasMoreBefore(infRef?.hasPrevious() || false)
setHasMoreAfter(infRef?.hasNext() || false)
- }
+ }, [infRef])
const fetchNext = () => {
if (infRef) {
@@ -27,7 +27,7 @@ export default ({ users }: { users: { data: User[] } }) => {
useEffect(() => {
updateStates()
- }, [infRef])
+ }, [infRef, updateStates])
return (
diff --git a/packages/react/test-app/Pages/InfiniteScroll/ShortContent.tsx b/packages/react/test-app/Pages/InfiniteScroll/ShortContent.tsx
index 90d20c4af..ea9f2217c 100644
--- a/packages/react/test-app/Pages/InfiniteScroll/ShortContent.tsx
+++ b/packages/react/test-app/Pages/InfiniteScroll/ShortContent.tsx
@@ -4,7 +4,7 @@ import { User } from './UserCard'
export default ({ users }: { users: { data: User[] } }) => {
return (
- {({ loadingPrevious, loadingNext }) => (
+ {() => (
{users.data.map((user) => (
diff --git a/packages/react/test-app/Pages/Links/AsComponent.tsx b/packages/react/test-app/Pages/Links/AsComponent.tsx
index 6b17de88d..6f882c2c1 100644
--- a/packages/react/test-app/Pages/Links/AsComponent.tsx
+++ b/packages/react/test-app/Pages/Links/AsComponent.tsx
@@ -3,13 +3,13 @@ import { useRef } from 'react'
declare global {
interface Window {
- componentEvents: Array<{ eventName: string; data: any; timestamp: number }>
+ componentEvents: Array<{ eventName: string; data: unknown; timestamp: number }>
}
}
window.componentEvents = []
-const CustomButton = ({ children, ...props }: { children: React.ReactNode; [key: string]: any }) => (
+const CustomButton = ({ children, ...props }: { children: React.ReactNode; [key: string]: unknown }) => (