From 8929a9f74fe7e39df23505957d83492a9d830f76 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 20:34:13 +1000 Subject: [PATCH 001/112] feat(svelte5): add Svelte 5 adapter and test app Introduce the Svelte 5 adapter for Inertia.js, including core components, utilities, configuration, and a comprehensive test application. Update documentation and test server logic to support Svelte 5 integration. --- CONTRIBUTING.md | 6 + package.json | 1 + packages/svelte5/.gitignore | 6 + packages/svelte5/LICENSE | 21 + packages/svelte5/package.json | 68 ++ packages/svelte5/readme.md | 3 + packages/svelte5/src/components/App.svelte | 103 +++ .../svelte5/src/components/Deferred.svelte | 34 + packages/svelte5/src/components/Form.svelte | 201 ++++++ packages/svelte5/src/components/Link.svelte | 82 +++ packages/svelte5/src/components/Render.svelte | 62 ++ .../svelte5/src/components/WhenVisible.svelte | 87 +++ packages/svelte5/src/createInertiaApp.ts | 66 ++ packages/svelte5/src/index.ts | 13 + packages/svelte5/src/link.ts | 264 ++++++++ packages/svelte5/src/page.ts | 14 + packages/svelte5/src/server.ts | 1 + packages/svelte5/src/types.ts | 13 + packages/svelte5/src/useForm.ts | 290 ++++++++ packages/svelte5/src/usePoll.ts | 28 + packages/svelte5/src/usePrefetch.ts | 53 ++ packages/svelte5/src/useRemember.ts | 13 + packages/svelte5/svelte.config.js | 15 + packages/svelte5/test-app/.gitignore | 4 + .../test-app/Layouts/NestedLayout.svelte | 20 + .../svelte5/test-app/Layouts/Prefetch.svelte | 16 + packages/svelte5/test-app/Layouts/SWR.svelte | 15 + .../test-app/Layouts/SiteLayout.svelte | 20 + .../test-app/Layouts/WithScrollRegion.svelte | 43 ++ .../Layouts/WithoutScrollRegion.svelte | 27 + .../svelte5/test-app/Pages/Article.svelte | 96 +++ .../Pages/ClientSideVisit/Page1.svelte | 70 ++ .../Pages/ClientSideVisit/Page2.svelte | 5 + .../test-app/Pages/DeepMergeProps.svelte | 37 + .../Pages/DeferredProps/InstantReload.svelte | 27 + .../Pages/DeferredProps/ManyGroups.svelte | 48 ++ .../test-app/Pages/DeferredProps/Page1.svelte | 23 + .../test-app/Pages/DeferredProps/Page2.svelte | 21 + packages/svelte5/test-app/Pages/Dump.svelte | 33 + .../svelte5/test-app/Pages/ErrorModal.svelte | 28 + packages/svelte5/test-app/Pages/Events.svelte | 638 ++++++++++++++++++ .../DisableWhileProcessing.svelte | 22 + .../Pages/FormComponent/DottedKeys.svelte | 35 + .../Pages/FormComponent/Elements.svelte | 110 +++ .../Pages/FormComponent/EmptyAction.svelte | 20 + .../Pages/FormComponent/Errors.svelte | 53 ++ .../Pages/FormComponent/Events.svelte | 123 ++++ .../Pages/FormComponent/Headers.svelte | 24 + .../Pages/FormComponent/InvalidateTags.svelte | 32 + .../Pages/FormComponent/Methods.svelte | 37 + .../Pages/FormComponent/Options.svelte | 106 +++ .../Pages/FormComponent/Progress.svelte | 50 ++ .../test-app/Pages/FormComponent/Ref.svelte | 67 ++ .../test-app/Pages/FormComponent/Reset.svelte | 193 ++++++ .../ResetAttributes/ResetOnError.svelte | 19 + .../ResetAttributes/ResetOnErrorFields.svelte | 19 + .../ResetAttributes/ResetOnSuccess.svelte | 19 + .../ResetOnSuccessFields.svelte | 19 + .../FormComponent/SetDefaultsOnSuccess.svelte | 21 + .../SubmitComplete/Defaults.svelte | 31 + .../SubmitComplete/Redirect.svelte | 20 + .../FormComponent/SubmitComplete/Reset.svelte | 27 + .../Pages/FormComponent/Transform.svelte | 53 ++ .../FormComponent/UppercaseMethod.svelte | 31 + .../Pages/FormComponent/Wayfinder.svelte | 30 + .../test-app/Pages/FormHelper/Data.svelte | 78 +++ .../test-app/Pages/FormHelper/Dirty.svelte | 58 ++ .../test-app/Pages/FormHelper/Errors.svelte | 75 ++ .../test-app/Pages/FormHelper/Events.svelte | 422 ++++++++++++ .../test-app/Pages/FormHelper/Methods.svelte | 53 ++ .../test-app/Pages/FormHelper/Nested.svelte | 72 ++ .../Pages/FormHelper/Transform.svelte | 60 ++ .../Pages/FormHelper/TypeScript/Child.svelte | 12 + .../Pages/FormHelper/TypeScript/Data.svelte | 29 + .../TypeScript/DynamicInputName.svelte | 21 + .../Pages/FormHelper/TypeScript/Errors.svelte | 86 +++ .../FormHelper/TypeScript/Generic.svelte | 9 + .../FormHelper/TypeScript/Nullable.svelte | 12 + .../TypeScript/OptionalProps.svelte | 20 + .../Pages/FormHelper/TypeScript/Parent.svelte | 12 + .../TypeScript/ValidationKey.svelte | 21 + .../test-app/Pages/History/Page.svelte | 17 + .../test-app/Pages/History/Version.svelte | 6 + packages/svelte5/test-app/Pages/Home.svelte | 44 ++ .../test-app/Pages/Links/AsWarning.svelte | 11 + .../Pages/Links/AsWarningFalse.svelte | 11 + .../Pages/Links/AutomaticCancellation.svelte | 16 + .../Pages/Links/CancelSyncRequest.svelte | 13 + .../Pages/Links/Data/AutoConverted.svelte | 20 + .../test-app/Pages/Links/Data/FormData.svelte | 20 + .../test-app/Pages/Links/Data/Object.svelte | 27 + .../test-app/Pages/Links/DataLoading.svelte | 8 + .../test-app/Pages/Links/Headers.svelte | 14 + .../test-app/Pages/Links/Location.svelte | 9 + .../test-app/Pages/Links/Method.svelte | 17 + .../Pages/Links/PartialReloads.svelte | 26 + .../test-app/Pages/Links/PathTraversal.svelte | 11 + .../Pages/Links/PreserveScroll.svelte | 60 ++ .../Pages/Links/PreserveScrollFalse.svelte | 55 ++ .../test-app/Pages/Links/PreserveState.svelte | 61 ++ .../test-app/Pages/Links/PropUpdate.svelte | 14 + .../test-app/Pages/Links/Reactivity.svelte | 37 + .../test-app/Pages/Links/Replace.svelte | 10 + .../test-app/Pages/Links/UrlFragments.svelte | 28 + .../test-app/Pages/MatchPropsOnKey.svelte | 53 ++ .../svelte5/test-app/Pages/MergeProps.svelte | 23 + .../RenderFunction/Nested/PageA.svelte | 21 + .../RenderFunction/Nested/PageB.svelte | 21 + .../RenderFunction/Simple/PageA.svelte | 18 + .../RenderFunction/Simple/PageB.svelte | 18 + .../Shorthand/Nested/PageA.svelte | 17 + .../Shorthand/Nested/PageB.svelte | 17 + .../Shorthand/Simple/PageA.svelte | 16 + .../Shorthand/Simple/PageB.svelte | 16 + .../svelte5/test-app/Pages/Poll/Hook.svelte | 12 + .../test-app/Pages/Poll/HookManual.svelte | 19 + .../test-app/Pages/Poll/RouterManual.svelte | 19 + .../test-app/Pages/Prefetch/AfterError.svelte | 16 + .../test-app/Pages/Prefetch/Form.svelte | 22 + .../test-app/Pages/Prefetch/Page.svelte | 13 + .../test-app/Pages/Prefetch/SWR.svelte | 13 + .../test-app/Pages/Prefetch/Tags.svelte | 78 +++ .../test-app/Pages/Prefetch/TestPage.svelte | 7 + .../test-app/Pages/Prefetch/Wayfinder.svelte | 57 ++ .../Remember/Components/ComponentA.svelte | 29 + .../Remember/Components/ComponentB.svelte | 29 + .../test-app/Pages/Remember/Default.svelte | 24 + .../Pages/Remember/FormHelper/Default.svelte | 47 ++ .../Pages/Remember/FormHelper/Remember.svelte | 52 ++ .../Pages/Remember/MultipleComponents.svelte | 33 + .../test-app/Pages/Remember/Object.svelte | 27 + .../Pages/Svelte/PropsAndPageStore.svelte | 38 ++ .../test-app/Pages/Visits/AfterError.svelte | 24 + .../Pages/Visits/AutomaticCancellation.svelte | 19 + .../Pages/Visits/Data/AutoConverted.svelte | 45 ++ .../Pages/Visits/Data/FormData.svelte | 53 ++ .../test-app/Pages/Visits/Data/Object.svelte | 82 +++ .../test-app/Pages/Visits/ErrorBags.svelte | 34 + .../test-app/Pages/Visits/Headers.svelte | 99 +++ .../test-app/Pages/Visits/Location.svelte | 13 + .../test-app/Pages/Visits/Method.svelte | 45 ++ .../Pages/Visits/PartialReloads.svelte | 121 ++++ .../Pages/Visits/PreserveScroll.svelte | 79 +++ .../Pages/Visits/PreserveScrollFalse.svelte | 79 +++ .../Pages/Visits/PreserveState.svelte | 98 +++ .../Pages/Visits/ReloadOnMount.svelte | 12 + .../test-app/Pages/Visits/Replace.svelte | 44 ++ .../test-app/Pages/Visits/UrlFragments.svelte | 57 ++ .../test-app/Pages/Visits/Wayfinder.svelte | 18 + .../svelte5/test-app/Pages/WhenVisible.svelte | 63 ++ packages/svelte5/test-app/app.ts | 21 + packages/svelte5/test-app/index.html | 14 + packages/svelte5/test-app/package.json | 21 + packages/svelte5/test-app/svelte.config.js | 15 + packages/svelte5/test-app/tsconfig.json | 20 + packages/svelte5/test-app/types.d.ts | 32 + packages/svelte5/test-app/vite-env.d.ts | 2 + packages/svelte5/test-app/vite.config.js | 14 + packages/svelte5/tsconfig.json | 25 + packages/svelte5/vite-with-deps.config.js | 18 + packages/svelte5/vite.config.js | 9 + playwright.config.ts | 4 +- pnpm-lock.yaml | 223 +++++- tests/app/server.js | 3 +- 164 files changed, 7503 insertions(+), 9 deletions(-) create mode 100755 packages/svelte5/.gitignore create mode 100755 packages/svelte5/LICENSE create mode 100644 packages/svelte5/package.json create mode 100755 packages/svelte5/readme.md create mode 100644 packages/svelte5/src/components/App.svelte create mode 100644 packages/svelte5/src/components/Deferred.svelte create mode 100644 packages/svelte5/src/components/Form.svelte create mode 100644 packages/svelte5/src/components/Link.svelte create mode 100644 packages/svelte5/src/components/Render.svelte create mode 100644 packages/svelte5/src/components/WhenVisible.svelte create mode 100644 packages/svelte5/src/createInertiaApp.ts create mode 100644 packages/svelte5/src/index.ts create mode 100644 packages/svelte5/src/link.ts create mode 100644 packages/svelte5/src/page.ts create mode 100644 packages/svelte5/src/server.ts create mode 100644 packages/svelte5/src/types.ts create mode 100644 packages/svelte5/src/useForm.ts create mode 100644 packages/svelte5/src/usePoll.ts create mode 100644 packages/svelte5/src/usePrefetch.ts create mode 100644 packages/svelte5/src/useRemember.ts create mode 100644 packages/svelte5/svelte.config.js create mode 100644 packages/svelte5/test-app/.gitignore create mode 100644 packages/svelte5/test-app/Layouts/NestedLayout.svelte create mode 100644 packages/svelte5/test-app/Layouts/Prefetch.svelte create mode 100644 packages/svelte5/test-app/Layouts/SWR.svelte create mode 100644 packages/svelte5/test-app/Layouts/SiteLayout.svelte create mode 100644 packages/svelte5/test-app/Layouts/WithScrollRegion.svelte create mode 100644 packages/svelte5/test-app/Layouts/WithoutScrollRegion.svelte create mode 100644 packages/svelte5/test-app/Pages/Article.svelte create mode 100644 packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte create mode 100644 packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte create mode 100644 packages/svelte5/test-app/Pages/DeepMergeProps.svelte create mode 100644 packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte create mode 100644 packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte create mode 100644 packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte create mode 100644 packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte create mode 100644 packages/svelte5/test-app/Pages/Dump.svelte create mode 100644 packages/svelte5/test-app/Pages/ErrorModal.svelte create mode 100644 packages/svelte5/test-app/Pages/Events.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Elements.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Errors.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Events.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Headers.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Methods.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Options.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Progress.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Ref.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Reset.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Transform.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/UppercaseMethod.svelte create mode 100644 packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Data.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Errors.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Events.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Methods.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Nested.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/Transform.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Data.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/DynamicInputName.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Errors.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Generic.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/Parent.svelte create mode 100644 packages/svelte5/test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte create mode 100644 packages/svelte5/test-app/Pages/History/Page.svelte create mode 100644 packages/svelte5/test-app/Pages/History/Version.svelte create mode 100644 packages/svelte5/test-app/Pages/Home.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/AsWarning.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Data/FormData.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Data/Object.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/DataLoading.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Headers.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Location.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Method.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PartialReloads.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PathTraversal.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PreserveState.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/PropUpdate.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Reactivity.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/Replace.svelte create mode 100644 packages/svelte5/test-app/Pages/Links/UrlFragments.svelte create mode 100644 packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte create mode 100644 packages/svelte5/test-app/Pages/MergeProps.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte create mode 100644 packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte create mode 100644 packages/svelte5/test-app/Pages/Poll/Hook.svelte create mode 100644 packages/svelte5/test-app/Pages/Poll/HookManual.svelte create mode 100644 packages/svelte5/test-app/Pages/Poll/RouterManual.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/AfterError.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/Form.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/Page.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/SWR.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/Tags.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/TestPage.svelte create mode 100644 packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/Components/ComponentA.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/Components/ComponentB.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/Default.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/FormHelper/Default.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/MultipleComponents.svelte create mode 100644 packages/svelte5/test-app/Pages/Remember/Object.svelte create mode 100644 packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/AfterError.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/AutomaticCancellation.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Data/AutoConverted.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Data/FormData.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Data/Object.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/ErrorBags.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Headers.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Location.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Method.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/PreserveScrollFalse.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/PreserveState.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/ReloadOnMount.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Replace.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/UrlFragments.svelte create mode 100644 packages/svelte5/test-app/Pages/Visits/Wayfinder.svelte create mode 100644 packages/svelte5/test-app/Pages/WhenVisible.svelte create mode 100644 packages/svelte5/test-app/app.ts create mode 100644 packages/svelte5/test-app/index.html create mode 100644 packages/svelte5/test-app/package.json create mode 100644 packages/svelte5/test-app/svelte.config.js create mode 100644 packages/svelte5/test-app/tsconfig.json create mode 100644 packages/svelte5/test-app/types.d.ts create mode 100644 packages/svelte5/test-app/vite-env.d.ts create mode 100644 packages/svelte5/test-app/vite.config.js create mode 100644 packages/svelte5/tsconfig.json create mode 100644 packages/svelte5/vite-with-deps.config.js create mode 100644 packages/svelte5/vite.config.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c5f30b9f..304147934 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,8 @@ inertia/ │ │ └── test-app/ React test application │ ├── svelte/ Svelte adapter │ │ └── test-app/ Svelte test application +│ ├── svelte5/ Svelte 5 adapter +│ │ └── test-app/ Svelte 5 test application │ └── vue3/ Vue 3 adapter │ └── test-app/ Vue 3 test application ├── playgrounds/ Full Laravel applications for manual testing @@ -72,6 +74,7 @@ Run the test suite for a specific adapter: ```sh pnpm test:react pnpm test:svelte +pnpm test:svelte5 pnpm test:vue ``` @@ -109,6 +112,7 @@ All adapters use the same Node.js backend and Playwright test suite. The only di tests/app/server.js Shared Node.js backend ├── serves: react test app (when PACKAGE=react) ├── serves: svelte test app (when PACKAGE=svelte) +├── serves: svelte5 test app (when PACKAGE=svelte5) └── serves: vue test app (when PACKAGE=vue3) tests/*.spec.ts Shared Playwright test suite @@ -120,6 +124,7 @@ When running a test command, the correct adapter is selected automatically: | ------- | --------------- | ---------------- | -------------------------------------------------- | | React | `react` | 13716 | [http://localhost:13716/](http://localhost:13716/) | | Svelte | `svelte` | 13717 | [http://localhost:13717/](http://localhost:13717/) | +| Svelte5 | `svelte5` | 13718 | [http://localhost:13718/](http://localhost:13718/) | | Vue 3 | `vue3` | 13715 | [http://localhost:13715/](http://localhost:13715/) | ### Automatic Test Server Boot @@ -141,6 +146,7 @@ Or start an individual one: ```sh pnpm dev:test-app:react pnpm dev:test-app:svelte +pnpm dev:test-app:svelte5 pnpm dev:test-app:vue ``` diff --git a/package.json b/package.json index e0f03f409..de93c233d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "type-check:test-app:vue": "cd packages/vue3/test-app && pnpm run type-check", "test:react": "PACKAGE=react playwright test", "test:svelte": "PACKAGE=svelte playwright test", + "test:svelte5": "PACKAGE=svelte5 playwright test", "test:vue": "PACKAGE=vue3 playwright test", "playground:react": "cd playgrounds/react && composer run dev", "playground:svelte4": "cd playgrounds/svelte4 && composer run dev", diff --git a/packages/svelte5/.gitignore b/packages/svelte5/.gitignore new file mode 100755 index 000000000..46548ba2e --- /dev/null +++ b/packages/svelte5/.gitignore @@ -0,0 +1,6 @@ +dist +types +node_modules +package-lock.json +yarn.lock +.svelte-kit diff --git a/packages/svelte5/LICENSE b/packages/svelte5/LICENSE new file mode 100755 index 000000000..e018f1d26 --- /dev/null +++ b/packages/svelte5/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Jonathan Reinink + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/svelte5/package.json b/packages/svelte5/package.json new file mode 100644 index 000000000..8694a0815 --- /dev/null +++ b/packages/svelte5/package.json @@ -0,0 +1,68 @@ +{ + "name": "@inertiajs/svelte5", + "version": "2.1.10", + "license": "MIT", + "description": "The Svelte 5 adapter for Inertia.js", + "contributors": [ + "Brodie Nguyen " + ], + "homepage": "https://inertiajs.com/", + "repository": { + "type": "git", + "url": "https://github.com/inertiajs/inertia.git", + "directory": "packages/svelte5" + }, + "bugs": { + "url": "https://github.com/inertiajs/inertia/issues" + }, + "files": [ + "dist", + "!dist/**/*.test.*", + "!dist/**/*.spec.*" + ], + "type": "module", + "types": "./dist/index.d.ts", + "svelte": "./dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "svelte": "./dist/index.js" + }, + "./server": { + "types": "./dist/server.d.ts", + "svelte": "./dist/server.js" + } + }, + "scripts": { + "build": "pnpm package && publint", + "build:with-deps": "svelte-kit sync && vite build --config vite-with-deps.config.js", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "dev": "pnpm package --watch", + "es2020-check": "pnpm build:with-deps && es-check es2020 \"dist/**/*.js\" --checkFeatures --module --noCache --verbose", + "package": "svelte-kit sync && svelte-package --input src", + "prepublishOnly": "pnpm build" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.2.0", + "@sveltejs/kit": "^2.36.3", + "@sveltejs/package": "^2.3.4", + "@sveltejs/vite-plugin-svelte": "^6.2.0", + "axios": "^1.12.0", + "es-check": "^9.3.1", + "publint": "^0.2.10", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tslib": "^2.7.0", + "typescript": "^5.9.2", + "vite": "^6.3.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + }, + "dependencies": { + "@inertiajs/core": "workspace:*", + "@types/lodash-es": "^4.17.12", + "lodash-es": "^4.17.21" + } +} diff --git a/packages/svelte5/readme.md b/packages/svelte5/readme.md new file mode 100755 index 000000000..e1fcf75f3 --- /dev/null +++ b/packages/svelte5/readme.md @@ -0,0 +1,3 @@ +# Inertia.js Svelte Adapter + +Visit [inertiajs.com](https://inertiajs.com/) to learn more. diff --git a/packages/svelte5/src/components/App.svelte b/packages/svelte5/src/components/App.svelte new file mode 100644 index 000000000..df454db00 --- /dev/null +++ b/packages/svelte5/src/components/App.svelte @@ -0,0 +1,103 @@ + + + + + diff --git a/packages/svelte5/src/components/Deferred.svelte b/packages/svelte5/src/components/Deferred.svelte new file mode 100644 index 000000000..ab940cde9 --- /dev/null +++ b/packages/svelte5/src/components/Deferred.svelte @@ -0,0 +1,34 @@ + + +{#if loaded} + +{:else} + +{/if} diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte new file mode 100644 index 000000000..194e4cf1e --- /dev/null +++ b/packages/svelte5/src/components/Form.svelte @@ -0,0 +1,201 @@ + + +
+ + diff --git a/packages/svelte5/src/components/Link.svelte b/packages/svelte5/src/components/Link.svelte new file mode 100644 index 000000000..b4fa89834 --- /dev/null +++ b/packages/svelte5/src/components/Link.svelte @@ -0,0 +1,82 @@ + + + + + + diff --git a/packages/svelte5/src/components/Render.svelte b/packages/svelte5/src/components/Render.svelte new file mode 100644 index 000000000..895dec332 --- /dev/null +++ b/packages/svelte5/src/components/Render.svelte @@ -0,0 +1,62 @@ + + + + +{#if component} + + {#key children?.length === 0 ? key : null} + {#if children.length > 0} + + {#each children as child} + + {/each} + + {:else} + + {/if} + {/key} +{/if} diff --git a/packages/svelte5/src/components/WhenVisible.svelte b/packages/svelte5/src/components/WhenVisible.svelte new file mode 100644 index 000000000..dbd39bc26 --- /dev/null +++ b/packages/svelte5/src/components/WhenVisible.svelte @@ -0,0 +1,87 @@ + + +{#if always || !loaded} + +{/if} + +{#if loaded} + +{:else if $$slots.fallback} + +{/if} diff --git a/packages/svelte5/src/createInertiaApp.ts b/packages/svelte5/src/createInertiaApp.ts new file mode 100644 index 000000000..1b9ac02c0 --- /dev/null +++ b/packages/svelte5/src/createInertiaApp.ts @@ -0,0 +1,66 @@ +import { router, setupProgress, type InertiaAppResponse, type Page } from '@inertiajs/core' +import { escape } from 'lodash-es' +import type { ComponentType } from 'svelte' +import App, { type InertiaAppProps } from './components/App.svelte' +import type { ComponentResolver } from './types' + +type SvelteRenderResult = { html: string; head: string; css?: { code: string } } +type AppComponent = ComponentType & { render: (props: InertiaAppProps) => SvelteRenderResult } + +interface CreateInertiaAppProps { + id?: string + resolve: ComponentResolver + setup: (props: { + el: HTMLElement | null + App: AppComponent + props: InertiaAppProps + }) => void | App | SvelteRenderResult + progress?: + | false + | { + delay?: number + color?: string + includeCSS?: boolean + showSpinner?: boolean + } + page?: Page +} + +export default async function createInertiaApp({ + id = 'app', + resolve, + setup, + progress = {}, + page, +}: CreateInertiaAppProps): InertiaAppResponse { + const isServer = typeof window === 'undefined' + const el = isServer ? null : document.getElementById(id) + const initialPage: Page = page || JSON.parse(el?.dataset.page || '{}') + const resolveComponent = (name: string) => Promise.resolve(resolve(name)) + + const [initialComponent] = await Promise.all([ + resolveComponent(initialPage.component), + router.decryptHistory().catch(() => {}), + ]) + + const props: InertiaAppProps = { initialPage, initialComponent, resolveComponent } + + const svelteApp = setup({ + el, + App: App as unknown as AppComponent, + props, + }) + + if (isServer) { + const { html, head, css } = svelteApp as SvelteRenderResult + + return { + body: `
${html}
`, + head: [head, css ? `` : ''], + } + } + + if (progress) { + setupProgress(progress) + } +} diff --git a/packages/svelte5/src/index.ts b/packages/svelte5/src/index.ts new file mode 100644 index 000000000..f1e062da1 --- /dev/null +++ b/packages/svelte5/src/index.ts @@ -0,0 +1,13 @@ +export { router } from '@inertiajs/core' +export { default as Deferred } from './components/Deferred.svelte' +export { default as Form } from './components/Form.svelte' +export { default as Link } from './components/Link.svelte' +export { default as WhenVisible } from './components/WhenVisible.svelte' +export { default as createInertiaApp } from './createInertiaApp' +export { default as inertia } from './link' +export { default as page } from './page' +export { type ResolvedComponent } from './types' +export { default as useForm, type InertiaForm, type InertiaFormProps } from './useForm' +export { default as usePoll } from './usePoll' +export { default as usePrefetch } from './usePrefetch' +export { default as useRemember } from './useRemember' diff --git a/packages/svelte5/src/link.ts b/packages/svelte5/src/link.ts new file mode 100644 index 000000000..6a652d486 --- /dev/null +++ b/packages/svelte5/src/link.ts @@ -0,0 +1,264 @@ +import { + isUrlMethodPair, + mergeDataIntoQueryString, + router, + shouldIntercept, + shouldNavigate, + type CacheForOption, + type GlobalEventsMap, + type LinkComponentBaseProps, + type LinkPrefetchOption, + type Method, + type VisitOptions, +} from '@inertiajs/core' +import type { CancelTokenSource } from 'axios' +import type { ActionReturn } from 'svelte/action' + +type ActionEventHandlers = { + [K in keyof HTMLElementEventMap]?: (event: HTMLElementEventMap[K]) => void +} + +interface ActionElement extends HTMLElement { + href?: string +} + +type ActionParameters = Omit & Omit + +type SelectedEventKeys = + | 'start' + | 'progress' + | 'finish' + | 'before' + | 'cancel' + | 'success' + | 'error' + | 'prefetching' + | 'prefetched' +type SelectedGlobalEventsMap = Pick +type ActionAttributes = { + [K in keyof SelectedGlobalEventsMap as `on:${K}` | `on${K}`]?: ( + event: CustomEvent, + ) => void +} & { + 'on:cancel-token'?: (event: CustomEvent) => void + oncanceltoken?: (event: CustomEvent) => void +} + +function link( + node: ActionElement, + initialParams: ActionParameters = {}, +): ActionReturn { + let inFlightCount = 0 + let hoverTimeout: NodeJS.Timeout + + // Variables initialized and controlled by the "update" function + let prefetchModes: LinkPrefetchOption[] = [] + let cacheForValue: CacheForOption | CacheForOption[] + let cacheTags: string[] = [] + let method: Method + let href: string + let data + let baseParams: VisitOptions + let visitParams: VisitOptions + + const regularEvents: ActionEventHandlers = { + click: (event) => { + if (shouldIntercept(event)) { + event.preventDefault() + router.visit(href, visitParams) + } + }, + } + + const prefetchHoverEvents: ActionEventHandlers = { + mouseenter: () => (hoverTimeout = setTimeout(() => prefetch(), 75)), + mouseleave: () => clearTimeout(hoverTimeout), + click: regularEvents.click, + } + + const prefetchClickEvents: ActionEventHandlers = { + mousedown: (event) => { + if (shouldIntercept(event)) { + event.preventDefault() + prefetch() + } + }, + keydown: (event) => { + if (shouldIntercept(event) && shouldNavigate(event)) { + event.preventDefault() + prefetch() + } + }, + mouseup: (event) => { + event.preventDefault() + router.visit(href, visitParams) + }, + keyup: (event) => { + if (shouldNavigate(event)) { + event.preventDefault() + router.visit(href, visitParams) + } + }, + click: (event) => { + if (shouldIntercept(event)) { + // Let the mouseup/keyup event handle the visit + event.preventDefault() + } + }, + } + + function update({ cacheFor = 0, prefetch = false, cacheTags: cacheTagValues = [], ...params }: ActionParameters) { + prefetchModes = (() => { + if (prefetch === true) { + return ['hover'] + } + + if (prefetch === false) { + return [] + } + + return Array.isArray(prefetch) ? prefetch : [prefetch] + })() + + cacheForValue = (() => { + if (cacheFor !== 0) { + // If they've provided a value, respect it + return cacheFor + } + + if (prefetchModes.length === 1 && prefetchModes[0] === 'click') { + // If they've only provided a prefetch mode of 'click', + // we should only prefetch for the next request but not keep it around + return 0 + } + + // Otherwise, default to 30 seconds + return 30_000 + })() + + cacheTags = cacheTagValues + + method = isUrlMethodPair(params.href) ? params.href.method : (params.method?.toLowerCase() as Method) || 'get' + ;[href, data] = hrefAndData(method, params) + + if (node.tagName === 'A') { + node.href = href + } + + baseParams = { + data, + method, + replace: params.replace || false, + preserveScroll: params.preserveScroll || false, + preserveState: params.preserveState ?? method !== 'get', + only: params.only || [], + except: params.except || [], + headers: params.headers || {}, + async: params.async || false, + } + + visitParams = { + ...baseParams, + onStart: (visit) => { + inFlightCount++ + updateNodeAttributes() + return dispatchEvent('start', { detail: { visit } }) + }, + onProgress: (progress) => dispatchEvent('progress', { detail: { progress } }), + onFinish: (visit) => { + inFlightCount-- + updateNodeAttributes() + return dispatchEvent('finish', { detail: { visit } }) + }, + onBefore: (visit) => dispatchEvent('before', { cancelable: true, detail: { visit } }), + onCancel: () => dispatchEvent('cancel'), + onSuccess: (page) => dispatchEvent('success', { detail: { page } }), + onError: (errors) => dispatchEvent('error', { detail: { errors } }), + onCancelToken: (token) => dispatchEvent('cancel-token', { detail: { token } }), + onPrefetching: (visit) => dispatchEvent('prefetching', { detail: { visit } }), + onPrefetched: (response, visit) => dispatchEvent('prefetched', { detail: { response, visit } }), + } + + updateEventListeners() + } + + function dispatchEvent(type: string, detail = {}) { + return node.dispatchEvent(new CustomEvent(type, detail)) + } + + function hrefAndData(method: Method, params: ActionParameters) { + return mergeDataIntoQueryString( + method, + isUrlMethodPair(params.href) ? params.href.url : node.href || params.href || '', + params.data || {}, + params.queryStringArrayFormat || 'brackets', + ) + } + + function prefetch() { + router.prefetch( + href, + { + ...baseParams, + onPrefetching: (visit) => dispatchEvent('prefetching', { detail: { visit } }), + onPrefetched: (response, visit) => dispatchEvent('prefetched', { detail: { response, visit } }), + }, + { cacheFor: cacheForValue, cacheTags }, + ) + } + + function updateNodeAttributes() { + if (inFlightCount > 0) { + node.setAttribute('data-loading', '') + return + } + + node.removeAttribute('data-loading') + } + + function updateEventListeners() { + removeEventListeners() + + if (prefetchModes.includes('hover')) { + addEventListeners(prefetchHoverEvents) + return + } + + if (prefetchModes.includes('click')) { + addEventListeners(prefetchClickEvents) + return + } + + addEventListeners(regularEvents) + } + + function addEventListeners(eventHandlers: ActionEventHandlers) { + Object.entries(eventHandlers).forEach(([event, handler]) => { + node.addEventListener(event as keyof HTMLElementEventMap, handler as EventListener) + }) + } + + function removeEventListeners() { + ;[prefetchHoverEvents, prefetchClickEvents, regularEvents].forEach((eventHandlers) => { + Object.entries(eventHandlers).forEach(([event, handler]) => { + node.removeEventListener(event as keyof HTMLElementEventMap, handler as EventListener) + }) + }) + } + + function destroy() { + clearTimeout(hoverTimeout) + removeEventListeners() + } + + update(initialParams) + + // TODO: Confirm is this needs to rerun when "prefetchModes" changes + if (prefetchModes.includes('mount')) { + prefetch() + } + + return { update, destroy } +} + +export default link diff --git a/packages/svelte5/src/page.ts b/packages/svelte5/src/page.ts new file mode 100644 index 000000000..9480306b7 --- /dev/null +++ b/packages/svelte5/src/page.ts @@ -0,0 +1,14 @@ +import { type Page } from '@inertiajs/core' +import { writable } from 'svelte/store' + +type SveltePage = Omit & { + props: Page['props'] & { + [key: string]: any + } +} + +const { set, subscribe } = writable() + +export const setPage = set + +export default { subscribe } diff --git a/packages/svelte5/src/server.ts b/packages/svelte5/src/server.ts new file mode 100644 index 000000000..a3168b6e2 --- /dev/null +++ b/packages/svelte5/src/server.ts @@ -0,0 +1 @@ +export { default as default } from '@inertiajs/core/server' diff --git a/packages/svelte5/src/types.ts b/packages/svelte5/src/types.ts new file mode 100644 index 000000000..6367e9c7e --- /dev/null +++ b/packages/svelte5/src/types.ts @@ -0,0 +1,13 @@ +import type { ComponentType } from 'svelte' +import type { RenderFunction, RenderProps } from './components/Render.svelte' + +export type ComponentResolver = (name: string) => ResolvedComponent | Promise + +export type LayoutResolver = (h: RenderFunction, page: RenderProps) => RenderProps + +export type LayoutType = LayoutResolver | ComponentType | ComponentType[] + +export type ResolvedComponent = { + default: ComponentType + layout?: LayoutType +} diff --git a/packages/svelte5/src/useForm.ts b/packages/svelte5/src/useForm.ts new file mode 100644 index 000000000..2d034e3ce --- /dev/null +++ b/packages/svelte5/src/useForm.ts @@ -0,0 +1,290 @@ +import type { + ActiveVisit, + Errors, + ErrorValue, + FormDataErrors, + FormDataKeys, + FormDataType, + FormDataValues, + Method, + Page, + PendingVisit, + Progress, + RequestPayload, + UrlMethodPair, + VisitOptions, +} from '@inertiajs/core' +import { router } from '@inertiajs/core' +import type { AxiosProgressEvent } from 'axios' +import { cloneDeep, get, has, isEqual, set } from 'lodash-es' +import { writable, type Writable } from 'svelte/store' + +type InertiaFormStore = Writable> & InertiaForm + +type FormOptions = Omit + +export interface InertiaFormProps { + isDirty: boolean + errors: FormDataErrors + hasErrors: boolean + progress: Progress | null + wasSuccessful: boolean + recentlySuccessful: boolean + processing: boolean + setStore(data: TForm): void + setStore>(key: T, value: FormDataValues): void + data(): TForm + transform(callback: (data: TForm) => object): this + defaults(): this + defaults(fields: Partial): this + defaults>(field: T, value: FormDataValues): this + reset>(...fields: K[]): this + clearErrors>(...fields: K[]): this + resetAndClearErrors>(...fields: K[]): this + setError>(field: K, value: ErrorValue): this + setError(errors: FormDataErrors): this + submit: (...args: [Method, string, FormOptions?] | [UrlMethodPair, FormOptions?]) => void + get(url: string, options?: FormOptions): void + post(url: string, options?: FormOptions): void + put(url: string, options?: FormOptions): void + patch(url: string, options?: FormOptions): void + delete(url: string, options?: FormOptions): void + cancel(): void +} + +export type InertiaForm = InertiaFormProps & TForm + +export default function useForm>(data: TForm | (() => TForm)): InertiaFormStore +export default function useForm>( + rememberKey: string, + data: TForm | (() => TForm), +): InertiaFormStore +export default function useForm>( + rememberKeyOrData: string | TForm | (() => TForm), + maybeData?: TForm | (() => TForm), +): InertiaFormStore { + const rememberKey = typeof rememberKeyOrData === 'string' ? rememberKeyOrData : null + const inputData = (typeof rememberKeyOrData === 'string' ? maybeData : rememberKeyOrData) ?? {} + const data: TForm = typeof inputData === 'function' ? inputData() : (inputData as TForm) + const restored = rememberKey + ? (router.restore(rememberKey) as { data: TForm; errors: Record, string> } | null) + : null + let defaults = cloneDeep(data) + let cancelToken: { cancel: () => void } | null = null + let recentlySuccessfulTimeoutId: ReturnType | null = null + let transform = (data: TForm) => data as object + // Track if defaults was called manually during onSuccess to avoid + // overriding user's custom defaults with automatic behavior. + let defaultsCalledInOnSuccess = false + + const store = writable>({ + ...(restored ? restored.data : data), + isDirty: false, + errors: (restored ? restored.errors : {}) as FormDataErrors, + hasErrors: false, + progress: null, + wasSuccessful: false, + recentlySuccessful: false, + processing: false, + setStore(keyOrData: keyof InertiaFormProps | FormDataKeys | TForm, maybeValue = undefined) { + store.update((store) => { + return typeof keyOrData === 'string' ? set(store, keyOrData, maybeValue) : Object.assign(store, keyOrData) + }) + }, + data() { + return Object.keys(data).reduce((carry, key) => { + return set(carry, key, get(this, key)) + }, {} as TForm) + }, + transform(callback) { + transform = callback + return this + }, + defaults(fieldOrFields?: FormDataKeys | Partial, maybeValue?: unknown) { + defaultsCalledInOnSuccess = true + + if (typeof fieldOrFields === 'undefined') { + defaults = cloneDeep(this.data()) + } else { + defaults = + typeof fieldOrFields === 'string' + ? set(cloneDeep(defaults), fieldOrFields, maybeValue) + : Object.assign(cloneDeep(defaults), fieldOrFields) + } + + return this + }, + reset(...fields) { + const clonedData = cloneDeep(defaults) + if (fields.length === 0) { + this.setStore(clonedData) + } else { + this.setStore( + fields + .filter((key) => has(clonedData, key)) + .reduce((carry, key) => { + return set(carry, key, get(clonedData, key)) + }, {} as TForm), + ) + } + + return this + }, + setError(fieldOrFields: FormDataKeys | FormDataErrors, maybeValue?: ErrorValue) { + this.setStore('errors', { + ...this.errors, + ...((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as Errors), + }) + + return this + }, + clearErrors(...fields) { + this.setStore( + 'errors', + Object.keys(this.errors).reduce( + (carry, field) => ({ + ...carry, + ...(fields.length > 0 && !fields.includes(field) ? { [field]: this.errors[field] } : {}), + }), + {}, + ) as Errors, + ) + return this + }, + resetAndClearErrors(...fields) { + this.reset(...fields) + this.clearErrors(...fields) + return this + }, + submit(...args) { + const objectPassed = args[0] !== null && typeof args[0] === 'object' + + const method = objectPassed ? args[0].method : args[0] + const url = objectPassed ? args[0].url : args[1] + const options = (objectPassed ? args[1] : args[2]) ?? {} + + defaultsCalledInOnSuccess = false + + const data = transform(this.data()) as RequestPayload + + const _options: Omit = { + ...options, + onCancelToken: (token: { cancel: () => void }) => { + cancelToken = token + + if (options.onCancelToken) { + return options.onCancelToken(token) + } + }, + onBefore: (visit: PendingVisit) => { + this.setStore('wasSuccessful', false) + this.setStore('recentlySuccessful', false) + if (recentlySuccessfulTimeoutId) { + clearTimeout(recentlySuccessfulTimeoutId) + } + + if (options.onBefore) { + return options.onBefore(visit) + } + }, + onStart: (visit: PendingVisit) => { + this.setStore('processing', true) + + if (options.onStart) { + return options.onStart(visit) + } + }, + onProgress: (event?: AxiosProgressEvent) => { + this.setStore('progress', event as any) + + if (options.onProgress) { + return options.onProgress(event) + } + }, + onSuccess: async (page: Page) => { + this.setStore('processing', false) + this.setStore('progress', null) + this.clearErrors() + this.setStore('wasSuccessful', true) + this.setStore('recentlySuccessful', true) + recentlySuccessfulTimeoutId = setTimeout(() => this.setStore('recentlySuccessful', false), 2000) + + const onSuccess = options.onSuccess ? await options.onSuccess(page) : null + + if (!defaultsCalledInOnSuccess) { + this.defaults(cloneDeep(this.data())) + } + + return onSuccess + }, + onError: (errors: Errors) => { + this.setStore('processing', false) + this.setStore('progress', null) + this.clearErrors().setError(errors) + + if (options.onError) { + return options.onError(errors) + } + }, + onCancel: () => { + this.setStore('processing', false) + this.setStore('progress', null) + + if (options.onCancel) { + return options.onCancel() + } + }, + onFinish: (visit: ActiveVisit) => { + this.setStore('processing', false) + this.setStore('progress', null) + cancelToken = null + + if (options.onFinish) { + return options.onFinish(visit) + } + }, + } + + if (method === 'delete') { + router.delete(url, { ..._options, data }) + } else { + router[method](url, data, _options) + } + }, + get(url, options) { + this.submit('get', url, options) + }, + post(url, options) { + this.submit('post', url, options) + }, + put(url, options) { + this.submit('put', url, options) + }, + patch(url, options) { + this.submit('patch', url, options) + }, + delete(url, options) { + this.submit('delete', url, options) + }, + cancel() { + cancelToken?.cancel() + }, + } as InertiaForm) + + store.subscribe((form) => { + if (form.isDirty === isEqual(form.data(), defaults)) { + form.setStore('isDirty', !form.isDirty) + } + + const hasErrors = Object.keys(form.errors).length > 0 + if (form.hasErrors !== hasErrors) { + form.setStore('hasErrors', !form.hasErrors) + } + + if (rememberKey) { + router.remember({ data: form.data(), errors: form.errors }, rememberKey) + } + }) + + return store +} diff --git a/packages/svelte5/src/usePoll.ts b/packages/svelte5/src/usePoll.ts new file mode 100644 index 000000000..f9392458c --- /dev/null +++ b/packages/svelte5/src/usePoll.ts @@ -0,0 +1,28 @@ +import { router, type PollOptions, type ReloadOptions } from '@inertiajs/core' +import { onDestroy, onMount } from 'svelte' + +export default function usePoll( + interval: number, + requestOptions: ReloadOptions = {}, + options: PollOptions = { + keepAlive: false, + autoStart: true, + }, +) { + const { stop, start } = router.poll(interval, requestOptions, { + ...options, + autoStart: false, + }) + + onMount(() => { + if (options.autoStart ?? true) { + start() + } + }) + + onDestroy(() => { + stop() + }) + + return { stop, start } +} diff --git a/packages/svelte5/src/usePrefetch.ts b/packages/svelte5/src/usePrefetch.ts new file mode 100644 index 000000000..cc02f644b --- /dev/null +++ b/packages/svelte5/src/usePrefetch.ts @@ -0,0 +1,53 @@ +import { router, type VisitOptions } from '@inertiajs/core' +import { onDestroy, onMount } from 'svelte' +import { readonly, writable } from 'svelte/store' + +export default function usePrefetch(options: VisitOptions = {}) { + const isPrefetched = writable(false) + const isPrefetching = writable(false) + const lastUpdatedAt = writable(null) + + const cached = typeof window === 'undefined' ? null : router.getCached(window.location.pathname, options) + const inFlight = typeof window === 'undefined' ? null : router.getPrefetching(window.location.pathname, options) + + isPrefetched.set(cached !== null) + isPrefetching.set(inFlight !== null) + lastUpdatedAt.set(cached?.staleTimestamp || null) + + let removePrefetchedListener: () => void + let removePrefetchingListener: () => void + + onMount(() => { + removePrefetchingListener = router.on('prefetching', ({ detail }) => { + if (detail.visit.url.pathname === window.location.pathname) { + isPrefetching.set(true) + } + }) + + removePrefetchedListener = router.on('prefetched', ({ detail }) => { + if (detail.visit.url.pathname === window.location.pathname) { + isPrefetched.set(true) + isPrefetching.set(false) + } + }) + }) + + onDestroy(() => { + if (removePrefetchedListener) { + removePrefetchedListener() + } + + if (removePrefetchingListener) { + removePrefetchingListener() + } + }) + + return { + isPrefetched: readonly(isPrefetched), + isPrefetching: readonly(isPrefetching), + lastUpdatedAt: readonly(lastUpdatedAt), + flush() { + router.flush(window.location.pathname, options) + }, + } +} diff --git a/packages/svelte5/src/useRemember.ts b/packages/svelte5/src/useRemember.ts new file mode 100644 index 000000000..de6b6e034 --- /dev/null +++ b/packages/svelte5/src/useRemember.ts @@ -0,0 +1,13 @@ +import { router } from '@inertiajs/core' +import { onDestroy } from 'svelte' +import { writable } from 'svelte/store' + +export default function useRemember(initialState: State, key?: string) { + const restored = router.restore(key) as State | undefined + const store = writable(restored !== undefined ? restored : initialState) + const unsubscribe = store.subscribe((state) => router.remember(state, key)) + + onDestroy(unsubscribe) + + return store +} diff --git a/packages/svelte5/svelte.config.js b/packages/svelte5/svelte.config.js new file mode 100644 index 000000000..4f4401606 --- /dev/null +++ b/packages/svelte5/svelte.config.js @@ -0,0 +1,15 @@ +import adapter from '@sveltejs/adapter-auto' +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + kit: { + adapter: adapter(), + }, + files: { + lib: 'src', + }, +} + +export default config diff --git a/packages/svelte5/test-app/.gitignore b/packages/svelte5/test-app/.gitignore new file mode 100644 index 000000000..8c63586e4 --- /dev/null +++ b/packages/svelte5/test-app/.gitignore @@ -0,0 +1,4 @@ +cypress/videos +cypress/screenshots +app/dist +node_modules diff --git a/packages/svelte5/test-app/Layouts/NestedLayout.svelte b/packages/svelte5/test-app/Layouts/NestedLayout.svelte new file mode 100644 index 000000000..fed03ab31 --- /dev/null +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -0,0 +1,20 @@ + + +
+ Nested Layout + {createdAt} +
+ +
+
diff --git a/packages/svelte5/test-app/Layouts/Prefetch.svelte b/packages/svelte5/test-app/Layouts/Prefetch.svelte new file mode 100644 index 000000000..edd473c98 --- /dev/null +++ b/packages/svelte5/test-app/Layouts/Prefetch.svelte @@ -0,0 +1,16 @@ + + + diff --git a/packages/svelte5/test-app/Layouts/SWR.svelte b/packages/svelte5/test-app/Layouts/SWR.svelte new file mode 100644 index 000000000..cee0bd331 --- /dev/null +++ b/packages/svelte5/test-app/Layouts/SWR.svelte @@ -0,0 +1,15 @@ + + + diff --git a/packages/svelte5/test-app/Layouts/SiteLayout.svelte b/packages/svelte5/test-app/Layouts/SiteLayout.svelte new file mode 100644 index 000000000..734e59089 --- /dev/null +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -0,0 +1,20 @@ + + +
+ Site Layout + {createdAt} +
+ +
+
diff --git a/packages/svelte5/test-app/Layouts/WithScrollRegion.svelte b/packages/svelte5/test-app/Layouts/WithScrollRegion.svelte new file mode 100644 index 000000000..788b99bdf --- /dev/null +++ b/packages/svelte5/test-app/Layouts/WithScrollRegion.svelte @@ -0,0 +1,43 @@ + + + + + + +
+ With scroll regions +
Document scroll position is {documentScrollLeft} & {documentScrollTop}
+
+ Slot scroll position is {slotScrollLeft} & {slotScrollTop} +
+ +
+
+
diff --git a/packages/svelte5/test-app/Layouts/WithoutScrollRegion.svelte b/packages/svelte5/test-app/Layouts/WithoutScrollRegion.svelte new file mode 100644 index 000000000..51d94a152 --- /dev/null +++ b/packages/svelte5/test-app/Layouts/WithoutScrollRegion.svelte @@ -0,0 +1,27 @@ + + + + +
+ Without scroll regions +
Document scroll position is {documentScrollLeft} & {documentScrollTop}
+
+ Slot scroll position is {slotScrollLeft} & {slotScrollTop} +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/Article.svelte b/packages/svelte5/test-app/Pages/Article.svelte new file mode 100644 index 000000000..6b6b2afca --- /dev/null +++ b/packages/svelte5/test-app/Pages/Article.svelte @@ -0,0 +1,96 @@ + + +

Article Header

+
+

+ Sunt culpa sit sunt enim aliquip. Esse ea ea quis voluptate. Enim consectetur aliqua ex ex magna cupidatat id minim + sit elit. Amet pariatur occaecat pariatur duis eiusmod dolore magna. Et commodo cupidatat in commodo elit cupidatat + minim qui id non enim ad. Culpa aliquip ad Lorem sit consectetur ullamco culpa duis nisi et fugiat mollit eiusmod. + Laboris voluptate veniam consequat proident in nulla irure velit. +

+

+ Sit sint laboris sunt eiusmod ipsum laborum eiusmod amet commodo exercitation in duis magna. Proident sunt minim in + elit qui. Id pariatur commodo fugiat excepteur in deserunt Lorem ipsum occaecat est. Excepteur sit tempor ipsum ex + officia veniam enim amet velit fugiat mollit cillum. Incididunt aliqua nulla id occaecat nulla. Non ea ad est + occaecat deserunt officia qui commodo exercitation. +

+

+ Voluptate laborum quis aliqua ullamco magna amet ullamco laborum qui cillum eu. Dolore dolore aliqua proident + proident sunt ipsum in. Enim velit dolore labore dolor quis incididunt duis culpa Lorem. Eu adipisicing non elit + fugiat voluptate labore ipsum dolore consectetur commodo. Et in et cillum duis consequat quis ex eu commodo. Eiusmod + aliqua excepteur consectetur eiusmod aute et consectetur sit pariatur dolore qui officia pariatur. +

+

+ Non sunt eu mollit qui reprehenderit. Aute culpa anim voluptate do in esse duis laborum ad dolore. Ullamco nisi in + nostrud officia do. Duis pariatur officia id duis. Deserunt ad incididunt est sint consectetur reprehenderit mollit + est Lorem ea pariatur anim dolor adipisicing. Nostrud irure magna nostrud laboris aute sunt veniam laboris veniam + incididunt sit. Nulla proident ad aliqua fugiat culpa sunt est in dolor velit ad irure nulla. +

+

+ Do aute laborum deserunt non laborum voluptate voluptate. Anim ut laborum magna sunt cupidatat irure. Cupidatat + fugiat minim sint cillum laborum excepteur irure id est irure ad occaecat adipisicing enim. Deserunt nulla anim + proident velit irure nostrud est est reprehenderit consequat pariatur qui. Fugiat Lorem sint eu laborum minim + pariatur cillum mollit nulla consequat ullamco ex. Ex consectetur ad ut irure fugiat occaecat aliqua exercitation + cillum ipsum anim dolore tempor. +

+

+ Adipisicing consequat irure fugiat Lorem deserunt aliquip do cupidatat. Lorem labore elit ex qui nostrud qui cillum + sunt adipisicing occaecat. Sunt nostrud amet amet cupidatat fugiat Lorem quis nulla id cillum esse eu. Ullamco + aliqua dolore irure amet mollit anim velit dolore. +

+

+ Veniam cupidatat ipsum ea officia ipsum nisi laborum culpa qui dolore. Aliqua Lorem nisi labore ea velit aliquip + irure excepteur eu. Laboris proident duis non labore sunt quis aute tempor laboris enim anim eiusmod. +

+

+ Minim proident ut aliqua ea ut culpa fugiat ullamco nisi esse nostrud reprehenderit id. Id id ullamco velit anim + nisi magna Lorem tempor. Et veniam occaecat ut labore consequat fugiat duis. +

+

+ Adipisicing ea consectetur adipisicing aute eu pariatur enim labore consequat occaecat consectetur minim nisi. + Cillum commodo sunt labore reprehenderit. Duis esse excepteur magna tempor eiusmod exercitation Lorem reprehenderit + excepteur pariatur. Esse cupidatat occaecat magna do aliquip Lorem. Consectetur adipisicing consequat dolore nostrud + esse eu cillum id commodo duis. Aliquip dolor cillum cupidatat fugiat. +

+

+ Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis + enim fugiat. Sint non quis consectetur voluptate aliqua dolore nulla. Irure sit reprehenderit sint laboris non elit. + Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum Lorem magna + consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate. +

+

Far down

+

+ Ex eiusmod id est laborum sunt ex ea aute adipisicing ad magna deserunt duis. Nostrud velit dolore id commodo quis + enim fugiat. Sint non quis consectetur voluptate aliqua dolore ad voluptate nulla. Irure sit reprehenderit sint + laboris non elit. Duis minim nisi esse dolor. Sit ex in consequat non occaecat commodo irure et. Commodo qui ipsum + Lorem magna consequat consequat et minim eiusmod Lorem eiusmod cupidatat voluptate. +

+
+ +
Scroll log: {JSON.stringify(scrollLog)}
+ +Home + +Article Far Down + + + + diff --git a/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte b/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte new file mode 100644 index 000000000..103d535ad --- /dev/null +++ b/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte @@ -0,0 +1,70 @@ + + +
+
{foo}
+
{bar}
+ + + + +
Errors: {errors}
+
Finished: {finished}
+
Success: {success}
+
diff --git a/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte b/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte new file mode 100644 index 000000000..6e8277280 --- /dev/null +++ b/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte @@ -0,0 +1,5 @@ + + +
{baz}
diff --git a/packages/svelte5/test-app/Pages/DeepMergeProps.svelte b/packages/svelte5/test-app/Pages/DeepMergeProps.svelte new file mode 100644 index 000000000..465d99902 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeepMergeProps.svelte @@ -0,0 +1,37 @@ + + +
bar count is {bar.length}
+
baz count is {baz.length}
+
foo.data count is {foo.data.length}
+
foo.page is {foo.page}
+
foo.per_page is {foo.per_page}
+
foo.meta.label is {foo.meta.label}
+ + diff --git a/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte b/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte new file mode 100644 index 000000000..03296516d --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte @@ -0,0 +1,27 @@ + + + + +
Loading foo...
+
+
{foo?.text}
+
+ + + +
Loading bar...
+
+
{bar?.text}
+
diff --git a/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte b/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte new file mode 100644 index 000000000..d718139e3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte @@ -0,0 +1,48 @@ + + + + +
Loading foo...
+
+ {foo?.text} +
+ + + +
Loading bar...
+
+ {bar?.text} +
+ + + +
Loading baz...
+
+ {baz?.text} +
+ + + +
Loading qux...
+
+ {qux?.text} +
+ + + +
Loading quux...
+
+ {quux?.text} +
+ +Page 1 +Page 2 +Many groups diff --git a/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte new file mode 100644 index 000000000..de559a389 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte @@ -0,0 +1,23 @@ + + + + +
Loading foo...
+
+ {foo?.text} +
+ + + +
Loading bar...
+
+ {bar?.text} +
+ +Page 1 +Page 2 diff --git a/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte b/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte new file mode 100644 index 000000000..b2e87c632 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte @@ -0,0 +1,21 @@ + + + +
Loading baz...
+ {baz} +
+ + +
Loading qux...
+ {qux} +
+ + +
Loading baz and qux...
+ both {baz} and {qux} +
diff --git a/packages/svelte5/test-app/Pages/Dump.svelte b/packages/svelte5/test-app/Pages/Dump.svelte new file mode 100644 index 000000000..7f378d11e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Dump.svelte @@ -0,0 +1,33 @@ + + +
+
This is Inertia page component containing a data dump of the request
+
+
{JSON.stringify(dump)}
+
diff --git a/packages/svelte5/test-app/Pages/ErrorModal.svelte b/packages/svelte5/test-app/Pages/ErrorModal.svelte new file mode 100644 index 000000000..e96fd4f60 --- /dev/null +++ b/packages/svelte5/test-app/Pages/ErrorModal.svelte @@ -0,0 +1,28 @@ + + +
+ e.key === 'Enter' && invalidVisit()} + role="button" + tabindex="0" + class="invalid-visit">Invalid Visit + e.key === 'Enter' && invalidVisitJson()} + role="button" + tabindex="0" + class="invalid-visit-json">Invalid Visit (JSON response) +
diff --git a/packages/svelte5/test-app/Pages/Events.svelte b/packages/svelte5/test-app/Pages/Events.svelte new file mode 100644 index 000000000..64e5bd21a --- /dev/null +++ b/packages/svelte5/test-app/Pages/Events.svelte @@ -0,0 +1,638 @@ + + + + +
+ + Basic Visit + Remove Inertia Listener + + + Before Event + Before Event (Prevent) + + + Before Event - Prevent globally using Inertia Event Listener + Before Event - Prevent globally using Native Event Listeners + + + Cancel Token Event + + + + Cancel Event + + + + Start Event + + + + Progress Event + Missing Progress Event (no files) + + + + + Error Event + Error Event (delaying onFinish w/ Promise) + + + + + Success Event + Success Event (delaying onFinish w/ Promise) + + + + + Invalid Event + + + Exception Event + + + Finish Event + + + + Navigate Event + + + + + + Lifecycle Success + Lifecycle Error + Lifecycle Cancel + Lifecycle Cancel - After Finish +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte new file mode 100644 index 000000000..ef1ef38ba --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte @@ -0,0 +1,22 @@ + + +
+

Form Disable While Processing Test

+ +
+
+ + {#if errors.name} +

{errors.name}

+ {/if} +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte b/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte new file mode 100644 index 000000000..74a6b701d --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte @@ -0,0 +1,35 @@ + + +
+

Dotted Keys Form Test

+ + +
+

Basic Dotted Keys

+ + + + + + +
+ + +
+

Escaped Dots

+ + + +
+ + +
+

Mixed Notation

+ + + + +
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte new file mode 100644 index 000000000..86ae9bb93 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte @@ -0,0 +1,110 @@ + + +
+

Form Elements

+ +
+ Form is {isDirty ? 'dirty' : 'clean'} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ + + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte new file mode 100644 index 000000000..b971d6f2e --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte @@ -0,0 +1,20 @@ + + +
+

Form Empty Action Test

+ +
+
+ + {#if errors.name} +

{errors.name}

+ {/if} +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte new file mode 100644 index 000000000..fc65a6526 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte @@ -0,0 +1,53 @@ + + +
+

Form Errors

+ + {#if hasErrors} +
Form has errors
+ {:else} +
No errors
+ {/if} + +
+ + +
{errors.name || ''}
+
+ +
+ + +
{errors.handle || ''}
+
+ +
+ + + + +
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Events.svelte b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte new file mode 100644 index 000000000..7b78899b9 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte @@ -0,0 +1,123 @@ + + +
+

Form Events & State

+ +
+ Events: {events.join(',')} +
+ +
+ Processing: {String(processing)} +
+ +
+ Progress: + {progress?.percentage || 0} + +
+ +
+ Was successful: {String(wasSuccessful)} +
+ +
+ Recently successful: {String(recentlySuccessful)} +
+ +
+ +
+ +
+ + + + + +
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Headers.svelte b/packages/svelte5/test-app/Pages/FormComponent/Headers.svelte new file mode 100644 index 000000000..2e66307ff --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Headers.svelte @@ -0,0 +1,24 @@ + + +
+

Form Headers

+ +
+ +
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte b/packages/svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte new file mode 100644 index 000000000..9075536dc --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte @@ -0,0 +1,32 @@ + + +
+ + +
+

Form Component with invalidateCacheTags

+
+ + +
+
+ +
+
Form Component Invalidate Tags Test Page
+
+ Last loaded at {lastLoaded} +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Methods.svelte b/packages/svelte5/test-app/Pages/FormComponent/Methods.svelte new file mode 100644 index 000000000..8eb599abb --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Methods.svelte @@ -0,0 +1,37 @@ + + +
+

HTTP Methods

+ +
+ + + + + +
+ +
Current method: {method}
+ +
+
+ +
+ +
+ + +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Options.svelte b/packages/svelte5/test-app/Pages/FormComponent/Options.svelte new file mode 100644 index 000000000..5261b2ac3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Options.svelte @@ -0,0 +1,106 @@ + + +
+

Form Options

+ + + + +
+ State: {state} +
+ +
+ + + + + + + + + + +
+ + {#if preserveScroll} +
+ {/if} + diff --git a/packages/svelte5/test-app/Pages/FormComponent/Progress.svelte b/packages/svelte5/test-app/Pages/FormComponent/Progress.svelte new file mode 100644 index 000000000..26e0f9340 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Progress.svelte @@ -0,0 +1,50 @@ + + +
+

Progress

+ +
+ Nprogress appearances: {nprogressAppearances} +
+ +
+ + +
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte b/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte new file mode 100644 index 000000000..301946794 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte @@ -0,0 +1,67 @@ + + +
+

Form Ref Test

+ +
+ +
Form is {isDirty ? 'dirty' : 'clean'}
+ {#if hasErrors} +
Form has errors
+ {/if} + {#if errors.name} +
{errors.name}
+ {/if} + +
+ +
+ +
+ +
+ +
+ +
+
+ +
+ + + + + + +
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Reset.svelte b/packages/svelte5/test-app/Pages/FormComponent/Reset.svelte new file mode 100644 index 000000000..f4fe054ac --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Reset.svelte @@ -0,0 +1,193 @@ + + + + +
+

Form Reset

+ + +

Basic Text Inputs

+ + + + +

Select Elements

+ + + + +

Radio Buttons

+ + +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +

Checkboxes

+ + +
+ + +
+ + +
+ + +
+ + +
+ + + + +
+ + +

Multiple Select Elements

+ + + + + + +

File Inputs & Textareas

+ + + + + + +

HTML5 Input Types

+ + + + + + + + + + + + +

Complex Nested Fields

+ + + + + + + + +

Special Cases

+ + + + + + + +

Dotted & Array Notation

+ + + + + + + + +

Numeric Values

+
+ + + +
+
+ + + +
+ + + + +

Submit

+ +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte new file mode 100644 index 000000000..dfdca9e51 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte @@ -0,0 +1,19 @@ + + +
+
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte new file mode 100644 index 000000000..50ef8b95d --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte @@ -0,0 +1,19 @@ + + +
+
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte new file mode 100644 index 000000000..87b8fd612 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte @@ -0,0 +1,19 @@ + + +
+
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte new file mode 100644 index 000000000..f072e84d8 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte @@ -0,0 +1,19 @@ + + +
+
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte new file mode 100644 index 000000000..aec47f021 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte @@ -0,0 +1,21 @@ + + +
+

{isDirty ? 'Form is dirty' : 'Form is clean'}

+ +
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + +
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte new file mode 100644 index 000000000..11184eadd --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte @@ -0,0 +1,31 @@ + + +
+

OnSubmitComplete Defaults Test

+ +
props.defaults()}> +
+

{isDirty ? 'Form is dirty' : 'Form is clean'}

+
+ +
+ + {#if errors.name} +

{errors.name}

+ {/if} +
+ +
+ + {#if errors.email} +

{errors.email}

+ {/if} +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte new file mode 100644 index 000000000..b63527595 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte @@ -0,0 +1,20 @@ + + +
+

Form Empty Action Test

+ +
props.reset('name')}> +
+ + {#if errors.name} +

{errors.name}

+ {/if} +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte new file mode 100644 index 000000000..7665e2aca --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte @@ -0,0 +1,27 @@ + + +
+

OnSubmitComplete Reset Test

+ +
props.reset('name')}> +
+ + {#if errors.name} +

{errors.name}

+ {/if} +
+ +
+ + {#if errors.email} +

{errors.email}

+ {/if} +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte b/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte new file mode 100644 index 000000000..9729cc62d --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte @@ -0,0 +1,53 @@ + + +
+

Transform Function

+ +
+ + + +
+ +
Current transform: {transformType}
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/UppercaseMethod.svelte b/packages/svelte5/test-app/Pages/FormComponent/UppercaseMethod.svelte new file mode 100644 index 000000000..f32a47553 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/UppercaseMethod.svelte @@ -0,0 +1,31 @@ + + +
+

Uppercase Method Test

+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte b/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte new file mode 100644 index 000000000..7189cd7da --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte @@ -0,0 +1,30 @@ + + +
+

Wayfinder Example

+ +
+
+ +
+ +
+ + +
+ +
+ +
+
+
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Data.svelte b/packages/svelte5/test-app/Pages/FormHelper/Data.svelte new file mode 100644 index 000000000..7c3727586 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Data.svelte @@ -0,0 +1,78 @@ + + +
+ + {#if $form.errors.name} + {$form.errors.name} + {/if} + + {#if $form.errors.handle} + {$form.errors.handle} + {/if} + + {#if $form.errors.remember} + {$form.errors.remember} + {/if} + + + + + + + + + + + + Form has {$form.hasErrors ? '' : 'no '}errors +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte b/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte new file mode 100644 index 000000000..61295151e --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte @@ -0,0 +1,58 @@ + + +
+
+ Form is {#if $form.isDirty}dirty{:else}clean{/if} +
+ + + + + + + + + + +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte b/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte new file mode 100644 index 000000000..e7865ef21 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte @@ -0,0 +1,75 @@ + + +
+ + {#if $form.errors.name} + {$form.errors.name} + {/if} + + {#if $form.errors.handle} + {$form.errors.handle} + {/if} + + {#if $form.errors.remember} + {$form.errors.remember} + {/if} + + + + + + + + + + + Form has {$form.hasErrors ? '' : 'no '}errors +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Events.svelte b/packages/svelte5/test-app/Pages/FormHelper/Events.svelte new file mode 100644 index 000000000..15d5dae20 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Events.svelte @@ -0,0 +1,422 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + Form was {$form.wasSuccessful ? '' : 'not '}successful + Form was {$form.recentlySuccessful ? '' : 'not '}recently successful + + + +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte b/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte new file mode 100644 index 000000000..bf5a4c1aa --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte @@ -0,0 +1,53 @@ + + +
+ + + + + + + + + +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Nested.svelte b/packages/svelte5/test-app/Pages/FormHelper/Nested.svelte new file mode 100644 index 000000000..497305581 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Nested.svelte @@ -0,0 +1,72 @@ + + +
+ + + + + + + + + Repository Tags + + + + +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte b/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte new file mode 100644 index 000000000..ecc9f3bc2 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte @@ -0,0 +1,60 @@ + + +
+ + + + + + + +
diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte new file mode 100644 index 000000000..68b042c46 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte @@ -0,0 +1,12 @@ + + +

Name: {form.name}

+

Email: {form.email}

diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Data.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Data.svelte new file mode 100644 index 000000000..7a2393ad4 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Data.svelte @@ -0,0 +1,29 @@ + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/DynamicInputName.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/DynamicInputName.svelte new file mode 100644 index 000000000..fe7e5beb6 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/DynamicInputName.svelte @@ -0,0 +1,21 @@ + + + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Errors.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Errors.svelte new file mode 100644 index 000000000..4a5fa3899 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Errors.svelte @@ -0,0 +1,86 @@ + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Generic.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Generic.svelte new file mode 100644 index 000000000..073f82d40 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Generic.svelte @@ -0,0 +1,9 @@ + + +
{form}
diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte new file mode 100644 index 000000000..4f66351c9 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte @@ -0,0 +1,12 @@ + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte new file mode 100644 index 000000000..7e3c7da1a --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte @@ -0,0 +1,20 @@ + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Parent.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Parent.svelte new file mode 100644 index 000000000..5aa0422d4 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Parent.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte new file mode 100644 index 000000000..79afe35e7 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte @@ -0,0 +1,21 @@ + diff --git a/packages/svelte5/test-app/Pages/History/Page.svelte b/packages/svelte5/test-app/Pages/History/Page.svelte new file mode 100644 index 000000000..7145e026f --- /dev/null +++ b/packages/svelte5/test-app/Pages/History/Page.svelte @@ -0,0 +1,17 @@ + + +Page 1 +Page 2 +Page 3 +Page 4 +Page 5 + + + +
This is page {pageNumber}.
+
Multi byte character: {multiByte}
diff --git a/packages/svelte5/test-app/Pages/History/Version.svelte b/packages/svelte5/test-app/Pages/History/Version.svelte new file mode 100644 index 000000000..7a4b8a405 --- /dev/null +++ b/packages/svelte5/test-app/Pages/History/Version.svelte @@ -0,0 +1,6 @@ + + +Page 1 +Page 2 diff --git a/packages/svelte5/test-app/Pages/Home.svelte b/packages/svelte5/test-app/Pages/Home.svelte new file mode 100644 index 000000000..a39e8a53d --- /dev/null +++ b/packages/svelte5/test-app/Pages/Home.svelte @@ -0,0 +1,44 @@ + + +
+ This is the Test App Entrypoint page + + Basic Links + 'Replace' Links + + Manual basic visits + Manual 'Replace' visits + + + Manual Redirect visit + + + Manual External Redirect visit +
diff --git a/packages/svelte5/test-app/Pages/Links/AsWarning.svelte b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte new file mode 100644 index 000000000..dbc998c9e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte @@ -0,0 +1,11 @@ + + +
+ This is the links page that demonstrates inertia-links with an 'as' warning + + {method} Link +
diff --git a/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte new file mode 100644 index 000000000..0fd8eec12 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte @@ -0,0 +1,11 @@ + + +
+ This is the links page that demonstrates inertia-links without the 'as' warning + + +
diff --git a/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte b/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte new file mode 100644 index 000000000..d8d2e2f45 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte @@ -0,0 +1,16 @@ + + +
+ This is the links page that demonstrates that only one visit can be active at a time + console.log('cancelled')} + on:start={() => console.log('started')} + class="visit" + > + Link + +
diff --git a/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte new file mode 100644 index 000000000..37059c04c --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte @@ -0,0 +1,13 @@ + + +

+ Page {page} +

+ +Go to Page 1 +Go to Page 2 +Go to Page 3 diff --git a/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte b/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte new file mode 100644 index 000000000..57247dcd7 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte @@ -0,0 +1,20 @@ + + +
+ This is the links page that demonstrates the automatic conversion of plain objects to form-data + + GET Link + + + + +
diff --git a/packages/svelte5/test-app/Pages/Links/Data/FormData.svelte b/packages/svelte5/test-app/Pages/Links/Data/FormData.svelte new file mode 100644 index 000000000..d1e608776 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Data/FormData.svelte @@ -0,0 +1,20 @@ + + +
+ This is the links page that demonstrates passing data through FormData objects + + GET Link + + + + +
diff --git a/packages/svelte5/test-app/Pages/Links/Data/Object.svelte b/packages/svelte5/test-app/Pages/Links/Data/Object.svelte new file mode 100644 index 000000000..06696ee23 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Data/Object.svelte @@ -0,0 +1,27 @@ + + +
+ This is the links page that demonstrates passing data through plain objects + + GET Link + + + + + + QSAF Defaults + QSAF Indices + QSAF Brackets +
diff --git a/packages/svelte5/test-app/Pages/Links/DataLoading.svelte b/packages/svelte5/test-app/Pages/Links/DataLoading.svelte new file mode 100644 index 000000000..3bb27b1e9 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/DataLoading.svelte @@ -0,0 +1,8 @@ + + +
+ First + Second +
diff --git a/packages/svelte5/test-app/Pages/Links/Headers.svelte b/packages/svelte5/test-app/Pages/Links/Headers.svelte new file mode 100644 index 000000000..29745fd93 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Headers.svelte @@ -0,0 +1,14 @@ + + +
+ This is the links page that demonstrates passing custom headers + Standard visit Link + + GET Link + +
diff --git a/packages/svelte5/test-app/Pages/Links/Location.svelte b/packages/svelte5/test-app/Pages/Links/Location.svelte new file mode 100644 index 000000000..143064e13 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Location.svelte @@ -0,0 +1,9 @@ + + +
+ This is the links page that demonstrates location visits inertia-links + + Location visit +
diff --git a/packages/svelte5/test-app/Pages/Links/Method.svelte b/packages/svelte5/test-app/Pages/Links/Method.svelte new file mode 100644 index 000000000..889eff06e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Method.svelte @@ -0,0 +1,17 @@ + + +
+ This is the links page that demonstrates inertia-link methods + + GET Link + + + + + + +
diff --git a/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte new file mode 100644 index 000000000..8809ba20b --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte @@ -0,0 +1,26 @@ + + +
+ This is the links page that demonstrates partial reloads + Foo is now {foo} + Bar is now {bar} + Baz is now {baz} +
{JSON.stringify(headers, null, 2)}
+ + Update All + Only foo + bar + Only baz + Except foo + bar + Except baz +
diff --git a/packages/svelte5/test-app/Pages/Links/PathTraversal.svelte b/packages/svelte5/test-app/Pages/Links/PathTraversal.svelte new file mode 100644 index 000000000..70796923e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PathTraversal.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte new file mode 100644 index 000000000..6cd928701 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte @@ -0,0 +1,60 @@ + + + + +
+ This is the links page that demonstrates scroll preservation with scroll regions + Foo is now {foo} + + + Preserve Scroll + + + Reset Scroll + + + + Preserve Scroll (Callback) + + + Reset Scroll (Callback) + + + Off-site link + + Article +
diff --git a/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte b/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte new file mode 100644 index 000000000..ad7bfc78a --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte @@ -0,0 +1,55 @@ + + + + +
+ This is the links page that demonstrates scroll preservation without scroll regions + Foo is now {foo} + + Preserve Scroll + Reset Scroll + + Preserve Scroll (Callback) + Reset Scroll (Callback) + + Off-site link +
diff --git a/packages/svelte5/test-app/Pages/Links/PreserveState.svelte b/packages/svelte5/test-app/Pages/Links/PreserveState.svelte new file mode 100644 index 000000000..2906139a7 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PreserveState.svelte @@ -0,0 +1,61 @@ + + + + +
+ This is the links page that demonstrates preserve state on Links + Foo is now {foo} + + + + [State] Preserve: true + + + [State] Preserve: false + + + [State] Preserve Callback: true + + + [State] Preserve Callback: false + +
diff --git a/packages/svelte5/test-app/Pages/Links/PropUpdate.svelte b/packages/svelte5/test-app/Pages/Links/PropUpdate.svelte new file mode 100644 index 000000000..9494cc679 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PropUpdate.svelte @@ -0,0 +1,14 @@ + + +
+ + The Link +
diff --git a/packages/svelte5/test-app/Pages/Links/Reactivity.svelte b/packages/svelte5/test-app/Pages/Links/Reactivity.svelte new file mode 100644 index 000000000..b3b585ee1 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Reactivity.svelte @@ -0,0 +1,37 @@ + + +
+ + This page demonstrates reactivity in Inertia links. Click the button to change the link properties. + + + Submit + + + + Prefetch Link + + +
diff --git a/packages/svelte5/test-app/Pages/Links/Replace.svelte b/packages/svelte5/test-app/Pages/Links/Replace.svelte new file mode 100644 index 000000000..7d55f284b --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/Replace.svelte @@ -0,0 +1,10 @@ + + +
+ This is the links page that demonstrates replace on Links + + [State] Replace: true + [State] Replace: false +
diff --git a/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte b/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte new file mode 100644 index 000000000..b1d709f33 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte @@ -0,0 +1,28 @@ + + + + +
+ This is the links page that demonstrates url fragment behaviour +
+ +
Document scroll position is {documentScrollLeft} & {documentScrollTop}
+ Basic link + Fragment link + Non-existent fragment link + +
This is the element with id 'target'
+
+
diff --git a/packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte b/packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte new file mode 100644 index 000000000..bb6a5e07d --- /dev/null +++ b/packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte @@ -0,0 +1,53 @@ + + +
bar count is {bar.length}
+
baz count is {baz.length}
+
foo.data count is {foo.data.length}
+
first foo.data name is {foo.data[0].name}
+
last foo.data name is {foo.data[foo.data.length - 1].name}
+
foo.companies count is {foo.companies.length}
+
first foo.companies name is {foo.companies[0].name}
+
last foo.companies name is {foo.companies[foo.companies.length - 1].name}
+
foo.teams count is {foo.teams.length}
+
first foo.teams name is {foo.teams[0].name}
+
last foo.teams name is {foo.teams[foo.teams.length - 1].name}
+
foo.page is {foo.page}
+
foo.per_page is {foo.per_page}
+
foo.meta.label is {foo.meta.label}
+ + diff --git a/packages/svelte5/test-app/Pages/MergeProps.svelte b/packages/svelte5/test-app/Pages/MergeProps.svelte new file mode 100644 index 000000000..dd5150844 --- /dev/null +++ b/packages/svelte5/test-app/Pages/MergeProps.svelte @@ -0,0 +1,23 @@ + + +
bar count is {bar.length}
+
foo count is {foo.length}
+ + diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte new file mode 100644 index 000000000..3c490629a --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte @@ -0,0 +1,21 @@ + + + + +
+ Nested Persistent Layout - Page A + Page B +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte new file mode 100644 index 000000000..bb2cc6463 --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte @@ -0,0 +1,21 @@ + + + + +
+ Nested Persistent Layout - Page B + Page A +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte new file mode 100644 index 000000000..045849e49 --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte @@ -0,0 +1,18 @@ + + + + +
+ Simple Persistent Layout - Page A + Page B +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte new file mode 100644 index 000000000..a676aaf7f --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte @@ -0,0 +1,18 @@ + + + + +
+ Simple Persistent Layout - Page B + Page A +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte new file mode 100644 index 000000000..d97763b3e --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte @@ -0,0 +1,17 @@ + + + + +
+ Nested Persistent Layout - Page A + Page B +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte new file mode 100644 index 000000000..655b7035f --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte @@ -0,0 +1,17 @@ + + + + +
+ Nested Persistent Layout - Page B + Page A +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte new file mode 100644 index 000000000..6eb6f083b --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte @@ -0,0 +1,16 @@ + + + + +
+ Simple Persistent Layout - Page A + Page B +
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte new file mode 100644 index 000000000..cdadd08bd --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte @@ -0,0 +1,16 @@ + + + + +
+ Simple Persistent Layout - Page B + Page A +
diff --git a/packages/svelte5/test-app/Pages/Poll/Hook.svelte b/packages/svelte5/test-app/Pages/Poll/Hook.svelte new file mode 100644 index 000000000..aa7488b30 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Poll/Hook.svelte @@ -0,0 +1,12 @@ + + +Home diff --git a/packages/svelte5/test-app/Pages/Poll/HookManual.svelte b/packages/svelte5/test-app/Pages/Poll/HookManual.svelte new file mode 100644 index 000000000..5c1923d58 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Poll/HookManual.svelte @@ -0,0 +1,19 @@ + + + + diff --git a/packages/svelte5/test-app/Pages/Poll/RouterManual.svelte b/packages/svelte5/test-app/Pages/Poll/RouterManual.svelte new file mode 100644 index 000000000..0c460e0c0 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Poll/RouterManual.svelte @@ -0,0 +1,19 @@ + + + + diff --git a/packages/svelte5/test-app/Pages/Prefetch/AfterError.svelte b/packages/svelte5/test-app/Pages/Prefetch/AfterError.svelte new file mode 100644 index 000000000..7e90b3958 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/AfterError.svelte @@ -0,0 +1,16 @@ + + +
+ + +
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Form.svelte b/packages/svelte5/test-app/Pages/Prefetch/Form.svelte new file mode 100644 index 000000000..9f552dbaf --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Form.svelte @@ -0,0 +1,22 @@ + + +
+

+ Random Value: {$page.props.randomValue} +

+ + + Back to Test Page +
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Page.svelte b/packages/svelte5/test-app/Pages/Prefetch/Page.svelte new file mode 100644 index 000000000..2576f75bb --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Page.svelte @@ -0,0 +1,13 @@ + + + + +
This is page {pageNumber}
+
+ Last loaded at {lastLoaded} +
diff --git a/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte b/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte new file mode 100644 index 000000000..0f42a6d2e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte @@ -0,0 +1,13 @@ + + + + +
This is page {pageNumber}
+
+ Last loaded at {lastLoaded} +
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte b/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte new file mode 100644 index 000000000..add6a0f14 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte @@ -0,0 +1,78 @@ + + +
+ +
+ + + +
+ +
+

Form Test

+
+ + +
+
+ +
+
This is tags page {pageNumber}
+
+ Last loaded at {lastLoaded} +
+
+
diff --git a/packages/svelte5/test-app/Pages/Prefetch/TestPage.svelte b/packages/svelte5/test-app/Pages/Prefetch/TestPage.svelte new file mode 100644 index 000000000..b751c0c51 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/TestPage.svelte @@ -0,0 +1,7 @@ + + +
+ Go to Prefetch Form +
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte b/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte new file mode 100644 index 000000000..fe63f6d2c --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte @@ -0,0 +1,57 @@ + + +
+

+ Is Prefetched: {isPrefetched} +

+

+ Is Prefetching: {isPrefetching} +

+ + + + +
diff --git a/packages/svelte5/test-app/Pages/Remember/Components/ComponentA.svelte b/packages/svelte5/test-app/Pages/Remember/Components/ComponentA.svelte new file mode 100644 index 000000000..c75535831 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/Components/ComponentA.svelte @@ -0,0 +1,29 @@ + + +
+ This component uses a string 'key' for the remember functionality. + + + +
diff --git a/packages/svelte5/test-app/Pages/Remember/Components/ComponentB.svelte b/packages/svelte5/test-app/Pages/Remember/Components/ComponentB.svelte new file mode 100644 index 000000000..045c1dbcd --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/Components/ComponentB.svelte @@ -0,0 +1,29 @@ + + +
+ This component uses a string 'key' for the remember functionality. + + + +
diff --git a/packages/svelte5/test-app/Pages/Remember/Default.svelte b/packages/svelte5/test-app/Pages/Remember/Default.svelte new file mode 100644 index 000000000..7b75ac08f --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/Default.svelte @@ -0,0 +1,24 @@ + + +
+ + + + + Navigate away +
diff --git a/packages/svelte5/test-app/Pages/Remember/FormHelper/Default.svelte b/packages/svelte5/test-app/Pages/Remember/FormHelper/Default.svelte new file mode 100644 index 000000000..3716d73c5 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/FormHelper/Default.svelte @@ -0,0 +1,47 @@ + + +
+ + {#if $form.errors.name} + {$form.errors.name} + {/if} + + {#if $form.errors.handle} + {$form.errors.handle} + {/if} + + {#if $form.errors.remember} + {$form.errors.remember} + {/if} + + + + + Navigate away +
diff --git a/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte b/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte new file mode 100644 index 000000000..5e7f3acf4 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte @@ -0,0 +1,52 @@ + + +
+ + {#if $form.errors.name} + {$form.errors.name} + {/if} + + {#if $form.errors.handle} + {$form.errors.handle} + {/if} + + {#if $form.errors.remember} + {$form.errors.remember} + {/if} + + + + + + Navigate away +
diff --git a/packages/svelte5/test-app/Pages/Remember/MultipleComponents.svelte b/packages/svelte5/test-app/Pages/Remember/MultipleComponents.svelte new file mode 100644 index 000000000..280c04624 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/MultipleComponents.svelte @@ -0,0 +1,33 @@ + + +
+ + + + + + + + Navigate away + Navigate off-site +
diff --git a/packages/svelte5/test-app/Pages/Remember/Object.svelte b/packages/svelte5/test-app/Pages/Remember/Object.svelte new file mode 100644 index 000000000..83c895e2a --- /dev/null +++ b/packages/svelte5/test-app/Pages/Remember/Object.svelte @@ -0,0 +1,27 @@ + + +
+ + + + + Navigate away +
diff --git a/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte b/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte new file mode 100644 index 000000000..482295a99 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte @@ -0,0 +1,38 @@ + + +
+ +

foo prop is {foo}

+

$page.props.foo is {$page.props.foo}

+

pageProps.foo is {pageProps.foo}

+ + Bar + Baz + Home +
diff --git a/packages/svelte5/test-app/Pages/Visits/AfterError.svelte b/packages/svelte5/test-app/Pages/Visits/AfterError.svelte new file mode 100644 index 000000000..d1df995d9 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/AfterError.svelte @@ -0,0 +1,24 @@ + + + diff --git a/packages/svelte5/test-app/Pages/Visits/AutomaticCancellation.svelte b/packages/svelte5/test-app/Pages/Visits/AutomaticCancellation.svelte new file mode 100644 index 000000000..346b1beeb --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/AutomaticCancellation.svelte @@ -0,0 +1,19 @@ + + +
+ This is the page that demonstrates that only one visit can be active at a time + Link +
diff --git a/packages/svelte5/test-app/Pages/Visits/Data/AutoConverted.svelte b/packages/svelte5/test-app/Pages/Visits/Data/AutoConverted.svelte new file mode 100644 index 000000000..eee64d7a5 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Data/AutoConverted.svelte @@ -0,0 +1,45 @@ + + +
+ + This is the page that demonstrates automatic conversion of plain objects to form-data using manual visits + + + Visit Link + POST Link + PUT Link + PATCH Link + DELETE Link +
diff --git a/packages/svelte5/test-app/Pages/Visits/Data/FormData.svelte b/packages/svelte5/test-app/Pages/Visits/Data/FormData.svelte new file mode 100644 index 000000000..ce6f874f9 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Data/FormData.svelte @@ -0,0 +1,53 @@ + + +
+ This is the page that demonstrates manual visit data passing through FormData objects + + Visit Link + POST Link + PUT Link + PATCH Link + DELETE Link +
diff --git a/packages/svelte5/test-app/Pages/Visits/Data/Object.svelte b/packages/svelte5/test-app/Pages/Visits/Data/Object.svelte new file mode 100644 index 000000000..08864e467 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Data/Object.svelte @@ -0,0 +1,82 @@ + + +
+ This is the page that demonstrates manual visit data passing through plain objects + + Visit Link + GET Link + POST Link + PUT Link + PATCH Link + DELETE Link + + QSAF Defaults + QSAF Indices + QSAF Brackets + Delete Query Param +
diff --git a/packages/svelte5/test-app/Pages/Visits/ErrorBags.svelte b/packages/svelte5/test-app/Pages/Visits/ErrorBags.svelte new file mode 100644 index 000000000..132f88c7c --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/ErrorBags.svelte @@ -0,0 +1,34 @@ + + +
+ This is the page that demonstrates error bags using manual visits + Default visit + Basic visit + POST visit +
diff --git a/packages/svelte5/test-app/Pages/Visits/Headers.svelte b/packages/svelte5/test-app/Pages/Visits/Headers.svelte new file mode 100644 index 000000000..2c34c287f --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Headers.svelte @@ -0,0 +1,99 @@ + + +
+ This is the page that demonstrates passing custom headers through manual visits + + Standard visit Link + + Specific visit Link + GET Link + POST Link + PUT Link + PATCH Link + DELETE Link + + Overriden Link +
diff --git a/packages/svelte5/test-app/Pages/Visits/Location.svelte b/packages/svelte5/test-app/Pages/Visits/Location.svelte new file mode 100644 index 000000000..d3b024abe --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Location.svelte @@ -0,0 +1,13 @@ + + +
+ This is the page that demonstrates location visits + + Location visit +
diff --git a/packages/svelte5/test-app/Pages/Visits/Method.svelte b/packages/svelte5/test-app/Pages/Visits/Method.svelte new file mode 100644 index 000000000..317651fdf --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Method.svelte @@ -0,0 +1,45 @@ + + +
+ This is the page that demonstrates manual visit methods + + Standard visit Link + Specific visit Link + GET Link + POST Link + PUT Link + PATCH Link + DELETE Link +
diff --git a/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte new file mode 100644 index 000000000..d952bf344 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte @@ -0,0 +1,121 @@ + + +
+ This is the page that demonstrates partial reloads using manual visits + Foo is now {foo} + Bar is now {bar} + Baz is now {baz} +
{headers}
+ + Update All (visit) + 'Only' foo + bar (visit) + 'Only' baz (visit) + 'Except' foo + bar (visit) + 'Except' baz (visit) + + Update All (GET) + 'Only' foo + bar (GET) + 'Only' baz (GET) + 'Except' foo + bar (GET) + 'Except' baz (GET) +
diff --git a/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte b/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte new file mode 100644 index 000000000..f43fe668d --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte @@ -0,0 +1,79 @@ + + + + +
+ + This is the page that demonstrates scroll preservation with scroll regions when using manual visits + + Foo is now {foo} + + Preserve Scroll + Reset Scroll + Preserve Scroll (Callback) +
+ Reset Scroll (Callback) + Preserve Scroll (GET) + Reset Scroll (GET) + + Off-site link +
diff --git a/packages/svelte5/test-app/Pages/Visits/PreserveScrollFalse.svelte b/packages/svelte5/test-app/Pages/Visits/PreserveScrollFalse.svelte new file mode 100644 index 000000000..7612a0fa4 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/PreserveScrollFalse.svelte @@ -0,0 +1,79 @@ + + + + +
+ + This is the page that demonstrates scroll preservation without scroll regions when using manual visits + + Foo is now {foo} + + Preserve Scroll + Reset Scroll + Preserve Scroll (Callback) +
+ Reset Scroll (Callback) + Preserve Scroll (GET) + Reset Scroll (GET) + + Off-site link +
diff --git a/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte b/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte new file mode 100644 index 000000000..eb2650b1e --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte @@ -0,0 +1,98 @@ + + +
+ This is the page that demonstrates preserve state on manual visits + Foo is now {foo} + + + [State] Preserve visit: true + [State] Preserve visit: false + [State] Preserve Callback: true + [State] Preserve Callback: false + [State] Preserve GET: true + [State] Preserve GET: false +
diff --git a/packages/svelte5/test-app/Pages/Visits/ReloadOnMount.svelte b/packages/svelte5/test-app/Pages/Visits/ReloadOnMount.svelte new file mode 100644 index 000000000..bc31e124d --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/ReloadOnMount.svelte @@ -0,0 +1,12 @@ + + +
Name is {name}
diff --git a/packages/svelte5/test-app/Pages/Visits/Replace.svelte b/packages/svelte5/test-app/Pages/Visits/Replace.svelte new file mode 100644 index 000000000..cdbd9489a --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Replace.svelte @@ -0,0 +1,44 @@ + + +
+ This is the links page that demonstrates manual replace + + [State] Replace visit: true + [State] Replace visit: false + [State] Replace GET: true + [State] Replace GET: false +
diff --git a/packages/svelte5/test-app/Pages/Visits/UrlFragments.svelte b/packages/svelte5/test-app/Pages/Visits/UrlFragments.svelte new file mode 100644 index 000000000..5e608dfc0 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/UrlFragments.svelte @@ -0,0 +1,57 @@ + + + + +
+ This is the page that demonstrates url fragment behaviour using manual visits +
+ +
Document scroll position is {documentScrollLeft} & {documentScrollTop}
+ Basic visit + Fragment visit + Non-existent fragment visit + + Basic GET visit + Fragment GET visit + Non-existent fragment GET visit + +
This is the element with id 'target'
+
+
diff --git a/packages/svelte5/test-app/Pages/Visits/Wayfinder.svelte b/packages/svelte5/test-app/Pages/Visits/Wayfinder.svelte new file mode 100644 index 000000000..82321b7cd --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/Wayfinder.svelte @@ -0,0 +1,18 @@ + + + diff --git a/packages/svelte5/test-app/Pages/WhenVisible.svelte b/packages/svelte5/test-app/Pages/WhenVisible.svelte new file mode 100644 index 000000000..cb616a8bd --- /dev/null +++ b/packages/svelte5/test-app/Pages/WhenVisible.svelte @@ -0,0 +1,63 @@ + + +
+ + +
Loading first one...
+
+ +
First one is visible!
+
+
+ +
+ + +
Loading second one...
+
+ +
Second one is visible!
+
+
+ +
+ + +
Loading third one...
+
+ +
Third one is visible!
+
+
+ +
+ + +
Loading fourth one...
+
+
+
+ +
+ + +
Loading fifth one...
+
+ +
Count is now {count}
+
+
diff --git a/packages/svelte5/test-app/app.ts b/packages/svelte5/test-app/app.ts new file mode 100644 index 000000000..194f25397 --- /dev/null +++ b/packages/svelte5/test-app/app.ts @@ -0,0 +1,21 @@ +import { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte' + +window.testing = { Inertia: router } + +createInertiaApp({ + page: window.initialPage, + resolve: async (name) => { + const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true }) + + if (name === 'DeferredProps/InstantReload') { + // Add small delay to ensure the component is loaded after the initial page load + // This is for projects that don't use { eager: true } in import.meta.glob + await new Promise((resolve) => setTimeout(resolve, 50)) + } + + return pages[`./Pages/${name}.svelte`] + }, + setup({ el, App, props }) { + new App({ target: el!, props }) + }, +}) diff --git a/packages/svelte5/test-app/index.html b/packages/svelte5/test-app/index.html new file mode 100644 index 000000000..6c247ed86 --- /dev/null +++ b/packages/svelte5/test-app/index.html @@ -0,0 +1,14 @@ + + + + + Inertia Svelte - Testing Environment + + + + +
+ + diff --git a/packages/svelte5/test-app/package.json b/packages/svelte5/test-app/package.json new file mode 100644 index 000000000..f988e796a --- /dev/null +++ b/packages/svelte5/test-app/package.json @@ -0,0 +1,21 @@ +{ + "type": "module", + "scripts": { + "build": "vite build .", + "dev": "nodemon --watch . --watch ../../core/dist --watch ../../svelte/dist --ext js,ts,svelte,html,json --ignore dist/ --exec 'vite build .'", + "type-check": "svelte-check --tsconfig ./tsconfig.json" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.2.0", + "@tsconfig/svelte": "^5.0.4", + "nodemon": "^3.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.1.0", + "typescript": "^5.9.2", + "vite": "^6.3.0" + }, + "dependencies": { + "@inertiajs/core": "workspace:*", + "@inertiajs/svelte": "workspace:*" + } +} diff --git a/packages/svelte5/test-app/svelte.config.js b/packages/svelte5/test-app/svelte.config.js new file mode 100644 index 000000000..171e710a4 --- /dev/null +++ b/packages/svelte5/test-app/svelte.config.js @@ -0,0 +1,15 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +const config = { + onwarn(warning, onwarn) { + if (/A11y/.test(warning.message)) return + + onwarn(warning) + }, + + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: vitePreprocess(), +} + +export default config diff --git a/packages/svelte5/test-app/tsconfig.json b/packages/svelte5/test-app/tsconfig.json new file mode 100644 index 000000000..0946cb312 --- /dev/null +++ b/packages/svelte5/test-app/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "module": "ESNext", + "moduleResolution": "bundler", + "baseUrl": ".", + "paths": { + "@/*": ["./*"] + } + }, + "include": ["**/*.ts", "**/*.d.ts", "**/*.svelte"] +} diff --git a/packages/svelte5/test-app/types.d.ts b/packages/svelte5/test-app/types.d.ts new file mode 100644 index 000000000..d661c5c57 --- /dev/null +++ b/packages/svelte5/test-app/types.d.ts @@ -0,0 +1,32 @@ +import type { Method, Page, PageProps, Router } from '@inertiajs/core' + +declare global { + interface Window { + testing: { + Inertia: Router + } + initialPage: Page + _inertia_request_dump: { + headers: Record + method: Method + form: Record | undefined + files: MulterFile[] | object + query: Record + $page: Page + } + _inertia_page_key: string | undefined + _inertia_props: PageProps + _inertia_layout_id: number | string | undefined + _inertia_site_layout_props: PageProps + _inertia_nested_layout_id: number | string | undefined + _inertia_nested_layout_props: PageProps + _inertia_page_props: PageProps + _plugin_global_props: object + } + + interface ImportMeta { + readonly glob: (pattern: string, options: { eager: true }) => Record + } +} + +export type MulterFile = Express.Multer.File diff --git a/packages/svelte5/test-app/vite-env.d.ts b/packages/svelte5/test-app/vite-env.d.ts new file mode 100644 index 000000000..4078e7476 --- /dev/null +++ b/packages/svelte5/test-app/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/packages/svelte5/test-app/vite.config.js b/packages/svelte5/test-app/vite.config.js new file mode 100644 index 000000000..a483ecb29 --- /dev/null +++ b/packages/svelte5/test-app/vite.config.js @@ -0,0 +1,14 @@ +import { svelte } from '@sveltejs/vite-plugin-svelte' +import { defineConfig } from 'vite' + +export default defineConfig({ + build: { + sourcemap: 'inline', + }, + resolve: { + alias: { + '@': __dirname, + }, + }, + plugins: [svelte()], +}) diff --git a/packages/svelte5/tsconfig.json b/packages/svelte5/tsconfig.json new file mode 100644 index 000000000..c9499c0fa --- /dev/null +++ b/packages/svelte5/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "declaration": true, + "declarationDir": "dist", + + "module": "ES2020", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "preserveConstEnums": true, + "removeComments": true + } +} diff --git a/packages/svelte5/vite-with-deps.config.js b/packages/svelte5/vite-with-deps.config.js new file mode 100644 index 000000000..c2d1a73ac --- /dev/null +++ b/packages/svelte5/vite-with-deps.config.js @@ -0,0 +1,18 @@ +import { svelte } from '@sveltejs/vite-plugin-svelte' +import { defineConfig } from 'vite' + +export default defineConfig({ + plugins: [svelte()], + build: { + minify: false, + lib: { + entry: './src/index.ts', + formats: ['es'], + fileName: 'index', + }, + rollupOptions: { + // Only externalize Svelte (peer dependency) - bundle everything else + external: ['svelte', 'svelte/internal', 'svelte/store'], + }, + }, +}) diff --git a/packages/svelte5/vite.config.js b/packages/svelte5/vite.config.js new file mode 100644 index 000000000..4e2e46364 --- /dev/null +++ b/packages/svelte5/vite.config.js @@ -0,0 +1,9 @@ +import { sveltekit } from '@sveltejs/kit/vite' +import { defineConfig } from 'vite' + +export default defineConfig({ + build: { + minify: false, + }, + plugins: [sveltekit()], +}) diff --git a/playwright.config.ts b/playwright.config.ts index 0ab73404e..d37e3a641 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,10 +1,10 @@ import { defineConfig, devices } from '@playwright/test' const adapter = process.env.PACKAGE || 'vue3' -const adapterPorts = { vue3: 13715, react: 13716, svelte: 13717 } +const adapterPorts = { vue3: 13715, react: 13716, svelte: 13717, svelte5: 13718 } const url = `http://localhost:${adapterPorts[adapter]}` -const adapters = ['react', 'svelte', 'vue3'] +const adapters = ['react', 'svelte', 'vue3', 'svelte5'] if (!adapters.includes(adapter)) { throw new Error(`Invalid adapter package "${adapter}". Expected one of: ${adapters.join(', ')}.`) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fec34788..816922a6e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,10 +19,10 @@ importers: version: 4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)) prettier-plugin-svelte: specifier: ^3.2.3 - version: 3.4.0(prettier@3.6.2)(svelte@5.38.10) + version: 3.4.0(prettier@3.6.2)(svelte@5.39.4) prettier-plugin-tailwindcss: specifier: ^0.6.9 - version: 0.6.14(prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)))(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.38.10))(prettier@3.6.2) + version: 0.6.14(prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)))(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.4))(prettier@3.6.2) optionalDependencies: '@rollup/rollup-linux-x64-gnu': specifier: ^4.28.1 @@ -222,6 +222,86 @@ importers: specifier: ^5.4.20 version: 5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0) + packages/svelte5: + dependencies: + '@inertiajs/core': + specifier: workspace:* + version: link:../core + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + lodash-es: + specifier: ^4.17.21 + version: 4.17.21 + devDependencies: + '@sveltejs/adapter-auto': + specifier: ^3.2.0 + version: 3.3.1(@sveltejs/kit@2.43.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))) + '@sveltejs/kit': + specifier: ^2.36.3 + version: 2.43.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + '@sveltejs/package': + specifier: ^2.3.4 + version: 2.5.3(svelte@5.39.4)(typescript@5.9.2) + '@sveltejs/vite-plugin-svelte': + specifier: ^6.2.0 + version: 6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + axios: + specifier: ^1.12.0 + version: 1.12.1 + es-check: + specifier: ^9.3.1 + version: 9.3.1 + publint: + specifier: ^0.2.10 + version: 0.2.12 + svelte: + specifier: ^5.0.0 + version: 5.39.4 + svelte-check: + specifier: ^4.0.0 + version: 4.3.1(picomatch@4.0.3)(svelte@5.39.4)(typescript@5.9.2) + tslib: + specifier: ^2.7.0 + version: 2.8.1 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + vite: + specifier: ^6.3.0 + version: 6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + + packages/svelte5/test-app: + dependencies: + '@inertiajs/core': + specifier: workspace:* + version: link:../../core + '@inertiajs/svelte': + specifier: workspace:* + version: link:../../svelte + devDependencies: + '@sveltejs/vite-plugin-svelte': + specifier: ^3.1.2 + version: 3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)) + '@tsconfig/svelte': + specifier: ^5.0.4 + version: 5.0.5 + nodemon: + specifier: ^3.0.0 + version: 3.1.10 + svelte: + specifier: ^4.2.14 + version: 4.2.20 + svelte-check: + specifier: ^4.1.0 + version: 4.3.1(picomatch@4.0.3)(svelte@4.2.20)(typescript@5.9.2) + typescript: + specifier: ^5.9.2 + version: 5.9.2 + vite: + specifier: ^5.4.20 + version: 5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0) + packages/vue3: dependencies: '@inertiajs/core': @@ -1051,6 +1131,19 @@ packages: '@opentelemetry/api': optional: true + '@sveltejs/kit@2.43.1': + resolution: {integrity: sha512-H8eXW5TSziSvt9d5IJ5pPyWGhXQLdmq+17H9j7aofA/TsfSvG8ZIpTjObphFRNagfIyoFGyoB3lOzdsGHKiKpw==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.0.0 + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@sveltejs/package@2.5.1': resolution: {integrity: sha512-n0XRW7H7rD2AbdDsTD1KjXBztU96eMMuxPYwL9C+ZS8H8M1mS5NgmqFaSe8wKR40RU1KjLsqSWMnzsxRfG2j+A==} engines: {node: ^16.14 || >=18} @@ -1058,6 +1151,13 @@ packages: peerDependencies: svelte: ^3.44.0 || ^4.0.0 || ^5.0.0-next.1 + '@sveltejs/package@2.5.3': + resolution: {integrity: sha512-E8trf3nQRDsBoiUz52zc219M0lYnr/Sn/l7q3ZKQ90z9iYhwD/BufJPXb78t45n2Kqc+HfN6e0eN79pd1wKCSA==} + engines: {node: ^16.14 || >=18} + hasBin: true + peerDependencies: + svelte: ^3.44.0 || ^4.0.0 || ^5.0.0-next.1 + '@sveltejs/vite-plugin-svelte-inspector@2.1.0': resolution: {integrity: sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==} engines: {node: ^18.0.0 || >=20} @@ -1074,6 +1174,14 @@ packages: svelte: ^5.0.0 vite: ^6.0.0 + '@sveltejs/vite-plugin-svelte-inspector@5.0.1': + resolution: {integrity: sha512-ubWshlMk4bc8mkwWbg6vNvCeT7lGQojE3ijDh3QTR6Zr/R+GXxsGbyH4PExEPpiFmqPhYiVSVmHBjUcVc1JIrA==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + '@sveltejs/vite-plugin-svelte@3.1.2': resolution: {integrity: sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA==} engines: {node: ^18.0.0 || >=20} @@ -1088,6 +1196,13 @@ packages: svelte: ^5.0.0 vite: ^6.0.0 + '@sveltejs/vite-plugin-svelte@6.2.0': + resolution: {integrity: sha512-nJsV36+o7rZUDlrnSduMNl11+RoDE1cKqOI0yUEBCcqFoAZOk47TwD3dPKS2WmRutke9StXnzsPBslY7prDM9w==} + engines: {node: ^20.19 || ^22.12 || >=24} + peerDependencies: + svelte: ^5.0.0 + vite: ^6.3.0 || ^7.0.0 + '@tailwindcss/node@4.1.13': resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} @@ -2886,6 +3001,10 @@ packages: resolution: {integrity: sha512-UY+OhrWK7WI22bCZ00P/M3HtyWgwJPi9IxSRkoAE2MeAy6kl7ZlZWJZ8RaB+X4KD/G+wjis+cGVnVYaoqbzBqg==} engines: {node: '>=18'} + svelte@5.39.4: + resolution: {integrity: sha512-VU729KzEau1l6d6d25EnRQhdkwwYdTQxQrF8gdUfjZ3dCjrG7VmRMylMxx92ayO9/z5PKWpDrShJdzc4PGW1uA==} + engines: {node: '>=18'} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -3616,6 +3735,11 @@ snapshots: '@sveltejs/kit': 2.39.1(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)) import-meta-resolve: 4.2.0 + '@sveltejs/adapter-auto@3.3.1(@sveltejs/kit@2.43.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))': + dependencies: + '@sveltejs/kit': 2.43.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + import-meta-resolve: 4.2.0 + '@sveltejs/kit@2.39.1(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0))': dependencies: '@standard-schema/spec': 1.0.0 @@ -3635,6 +3759,25 @@ snapshots: svelte: 4.2.20 vite: 5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0) + '@sveltejs/kit@2.43.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + dependencies: + '@standard-schema/spec': 1.0.0 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) + '@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + '@types/cookie': 0.6.0 + acorn: 8.15.0 + cookie: 0.6.0 + devalue: 5.3.2 + esm-env: 1.2.2 + kleur: 4.1.5 + magic-string: 0.30.19 + mrmime: 2.0.1 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.2 + svelte: 5.39.4 + vite: 6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + '@sveltejs/package@2.5.1(svelte@4.2.20)(typescript@5.9.2)': dependencies: chokidar: 4.0.3 @@ -3646,6 +3789,17 @@ snapshots: transitivePeerDependencies: - typescript + '@sveltejs/package@2.5.3(svelte@5.39.4)(typescript@5.9.2)': + dependencies: + chokidar: 4.0.3 + kleur: 4.1.5 + sade: 1.8.1 + semver: 7.7.2 + svelte: 5.39.4 + svelte2tsx: 0.7.43(svelte@5.39.4)(typescript@5.9.2) + transitivePeerDependencies: + - typescript + '@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0))': dependencies: '@sveltejs/vite-plugin-svelte': 3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)) @@ -3664,6 +3818,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + debug: 4.4.1(supports-color@5.5.0) + svelte: 5.39.4 + vite: 6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + transitivePeerDependencies: + - supports-color + '@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0))': dependencies: '@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@4.2.20)(vite@5.4.20(@types/node@24.5.0)(lightningcss@1.30.1)(terser@5.44.0)) @@ -3691,6 +3854,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.0(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)))(svelte@5.39.4)(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + debug: 4.4.1(supports-color@5.5.0) + deepmerge: 4.3.1 + magic-string: 0.30.19 + svelte: 5.39.4 + vite: 6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + vitefu: 1.1.1(vite@6.3.6(@types/node@24.5.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + transitivePeerDependencies: + - supports-color + '@tailwindcss/node@4.1.13': dependencies: '@jridgewell/remapping': 2.3.5 @@ -5220,17 +5395,17 @@ snapshots: optionalDependencies: vue-tsc: 2.2.12(typescript@5.9.2) - prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.38.10): + prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.4): dependencies: prettier: 3.6.2 - svelte: 5.38.10 + svelte: 5.39.4 - prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)))(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.38.10))(prettier@3.6.2): + prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)))(prettier-plugin-svelte@3.4.0(prettier@3.6.2)(svelte@5.39.4))(prettier@3.6.2): dependencies: prettier: 3.6.2 optionalDependencies: prettier-plugin-organize-imports: 4.2.0(prettier@3.6.2)(typescript@5.9.2)(vue-tsc@2.2.12(typescript@5.9.2)) - prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@5.38.10) + prettier-plugin-svelte: 3.4.0(prettier@3.6.2)(svelte@5.39.4) prettier@3.6.2: {} @@ -5529,6 +5704,18 @@ snapshots: transitivePeerDependencies: - picomatch + svelte-check@4.3.1(picomatch@4.0.3)(svelte@5.39.4)(typescript@5.9.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + chokidar: 4.0.3 + fdir: 6.5.0(picomatch@4.0.3) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.39.4 + typescript: 5.9.2 + transitivePeerDependencies: + - picomatch + svelte-hmr@0.16.0(svelte@4.2.20): dependencies: svelte: 4.2.20 @@ -5540,6 +5727,13 @@ snapshots: svelte: 4.2.20 typescript: 5.9.2 + svelte2tsx@0.7.43(svelte@5.39.4)(typescript@5.9.2): + dependencies: + dedent-js: 1.0.1 + pascal-case: 3.1.2 + svelte: 5.39.4 + typescript: 5.9.2 + svelte@4.2.20: dependencies: '@ampproject/remapping': 2.3.0 @@ -5574,6 +5768,23 @@ snapshots: magic-string: 0.30.19 zimmerframe: 1.1.4 + svelte@5.39.4: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + esm-env: 1.2.2 + esrap: 2.1.0 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.19 + zimmerframe: 1.1.4 + table@6.9.0: dependencies: ajv: 8.17.1 diff --git a/tests/app/server.js b/tests/app/server.js index 53b42d9c2..28308b42d 100644 --- a/tests/app/server.js +++ b/tests/app/server.js @@ -10,7 +10,7 @@ app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json({ extended: true })) const upload = multer() -const adapters = ['react', 'svelte', 'vue3'] +const adapters = ['react', 'svelte', 'vue3', 'svelte5'] if (!adapters.includes(inertia.package)) { throw new Error(`Invalid adapter package "${inertia.package}". Expected one of: ${adapters.join(', ')}.`) @@ -759,6 +759,7 @@ const adapterPorts = { vue3: 13715, react: 13716, svelte: 13717, + svelte5: 13718, } showServerStatus(inertia.package, adapterPorts[inertia.package]) From f4a305c2449ff4368d4a74cdd160325d7b5f7452 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:42:10 +1000 Subject: [PATCH 002/112] refactor(test-app): update imports to @inertiajs/svelte5 Replaces all imports from '@inertiajs/svelte' with '@inertiajs/svelte5' across layouts, pages, and form helpers in the Svelte 5 test app. This aligns the codebase with the new package structure and ensures compatibility with the latest version. --- packages/svelte5/test-app/Layouts/NestedLayout.svelte | 2 +- packages/svelte5/test-app/Layouts/Prefetch.svelte | 2 +- packages/svelte5/test-app/Layouts/SWR.svelte | 2 +- packages/svelte5/test-app/Layouts/SiteLayout.svelte | 2 +- packages/svelte5/test-app/Pages/Article.svelte | 2 +- packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte | 2 +- packages/svelte5/test-app/Pages/DeepMergeProps.svelte | 2 +- .../svelte5/test-app/Pages/DeferredProps/InstantReload.svelte | 2 +- packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte | 2 +- packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte | 2 +- packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte | 2 +- packages/svelte5/test-app/Pages/ErrorModal.svelte | 2 +- .../test-app/Pages/FormComponent/DisableWhileProcessing.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Elements.svelte | 2 +- .../svelte5/test-app/Pages/FormComponent/EmptyAction.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Errors.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Events.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Headers.svelte | 2 +- .../svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Methods.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Options.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Progress.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Ref.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Reset.svelte | 2 +- .../Pages/FormComponent/ResetAttributes/ResetOnError.svelte | 2 +- .../FormComponent/ResetAttributes/ResetOnErrorFields.svelte | 2 +- .../Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte | 2 +- .../FormComponent/ResetAttributes/ResetOnSuccessFields.svelte | 2 +- .../test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte | 2 +- .../test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte | 2 +- .../test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte | 2 +- .../test-app/Pages/FormComponent/SubmitComplete/Reset.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Transform.svelte | 2 +- .../svelte5/test-app/Pages/FormComponent/UppercaseMethod.svelte | 2 +- packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte | 2 +- packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte | 2 +- packages/svelte5/test-app/Pages/FormHelper/Errors.svelte | 2 +- packages/svelte5/test-app/Pages/FormHelper/Methods.svelte | 2 +- packages/svelte5/test-app/Pages/FormHelper/Nested.svelte | 2 +- packages/svelte5/test-app/Pages/FormHelper/Transform.svelte | 2 +- .../svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte | 2 +- .../svelte5/test-app/Pages/FormHelper/TypeScript/Data.svelte | 2 +- .../Pages/FormHelper/TypeScript/DynamicInputName.svelte | 2 +- .../svelte5/test-app/Pages/FormHelper/TypeScript/Errors.svelte | 2 +- .../svelte5/test-app/Pages/FormHelper/TypeScript/Generic.svelte | 2 +- .../test-app/Pages/FormHelper/TypeScript/Nullable.svelte | 2 +- .../test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte | 2 +- .../svelte5/test-app/Pages/FormHelper/TypeScript/Parent.svelte | 2 +- .../test-app/Pages/FormHelper/TypeScript/ValidationKey.svelte | 2 +- packages/svelte5/test-app/Pages/History/Page.svelte | 2 +- packages/svelte5/test-app/Pages/History/Version.svelte | 2 +- packages/svelte5/test-app/Pages/Links/AsWarning.svelte | 2 +- packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte | 2 +- .../svelte5/test-app/Pages/Links/AutomaticCancellation.svelte | 2 +- packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Data/FormData.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Data/Object.svelte | 2 +- packages/svelte5/test-app/Pages/Links/DataLoading.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Headers.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Location.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Method.svelte | 2 +- packages/svelte5/test-app/Pages/Links/PartialReloads.svelte | 2 +- packages/svelte5/test-app/Pages/Links/PathTraversal.svelte | 2 +- packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte | 2 +- .../svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte | 2 +- packages/svelte5/test-app/Pages/Links/PreserveState.svelte | 2 +- packages/svelte5/test-app/Pages/Links/PropUpdate.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Reactivity.svelte | 2 +- packages/svelte5/test-app/Pages/Links/Replace.svelte | 2 +- packages/svelte5/test-app/Pages/Links/UrlFragments.svelte | 2 +- packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte | 2 +- packages/svelte5/test-app/Pages/MergeProps.svelte | 2 +- .../Pages/PersistentLayouts/RenderFunction/Nested/PageA.svelte | 2 +- .../Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte | 2 +- .../Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte | 2 +- .../Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte | 2 +- .../Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte | 2 +- .../Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte | 2 +- .../Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte | 2 +- .../Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte | 2 +- packages/svelte5/test-app/Pages/Poll/Hook.svelte | 2 +- packages/svelte5/test-app/Pages/Poll/HookManual.svelte | 2 +- packages/svelte5/test-app/Pages/Poll/RouterManual.svelte | 2 +- packages/svelte5/test-app/Pages/Prefetch/AfterError.svelte | 2 +- packages/svelte5/test-app/Pages/Prefetch/Form.svelte | 2 +- packages/svelte5/test-app/Pages/Prefetch/Tags.svelte | 2 +- packages/svelte5/test-app/Pages/Prefetch/TestPage.svelte | 2 +- packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte | 2 +- .../test-app/Pages/Remember/Components/ComponentA.svelte | 2 +- .../test-app/Pages/Remember/Components/ComponentB.svelte | 2 +- packages/svelte5/test-app/Pages/Remember/Default.svelte | 2 +- .../svelte5/test-app/Pages/Remember/FormHelper/Default.svelte | 2 +- .../svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte | 2 +- .../svelte5/test-app/Pages/Remember/MultipleComponents.svelte | 2 +- packages/svelte5/test-app/Pages/Remember/Object.svelte | 2 +- packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/AfterError.svelte | 2 +- .../svelte5/test-app/Pages/Visits/AutomaticCancellation.svelte | 2 +- .../svelte5/test-app/Pages/Visits/Data/AutoConverted.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Data/FormData.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Data/Object.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/ErrorBags.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Headers.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Location.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Method.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte | 2 +- .../svelte5/test-app/Pages/Visits/PreserveScrollFalse.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/PreserveState.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/ReloadOnMount.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Replace.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/UrlFragments.svelte | 2 +- packages/svelte5/test-app/Pages/Visits/Wayfinder.svelte | 2 +- packages/svelte5/test-app/Pages/WhenVisible.svelte | 2 +- packages/svelte5/test-app/app.ts | 2 +- packages/svelte5/test-app/package.json | 2 +- 118 files changed, 118 insertions(+), 118 deletions(-) diff --git a/packages/svelte5/test-app/Layouts/NestedLayout.svelte b/packages/svelte5/test-app/Layouts/NestedLayout.svelte index fed03ab31..088fe7d5b 100644 --- a/packages/svelte5/test-app/Layouts/NestedLayout.svelte +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -1,6 +1,6 @@
diff --git a/packages/svelte5/test-app/Layouts/SWR.svelte b/packages/svelte5/test-app/Layouts/SWR.svelte index cee0bd331..3d9fe18d2 100644 --- a/packages/svelte5/test-app/Layouts/SWR.svelte +++ b/packages/svelte5/test-app/Layouts/SWR.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Layouts/SiteLayout.svelte b/packages/svelte5/test-app/Layouts/SiteLayout.svelte index 734e59089..de69a29ae 100644 --- a/packages/svelte5/test-app/Layouts/SiteLayout.svelte +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -1,6 +1,6 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte b/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte index 74a6b701d..77fdb1ae8 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/DottedKeys.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte index 86ae9bb93..2c32b7000 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte index b971d6f2e..ef8997114 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte index fc65a6526..8a2108920 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/Events.svelte b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte index 7b78899b9..57fb50d7d 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Events.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte index 50ef8b95d..da5d6a291 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte index 87b8fd612..84530b4ba 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte index f072e84d8..314636cb1 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte index aec47f021..7dde16296 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte index 11184eadd..25ca9bbd2 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte index b63527595..f79d1e86e 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte index 7665e2aca..5103f0d0b 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte b/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte index 9729cc62d..63045a191 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Transform.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte b/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte index 7189cd7da..9119f895b 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Wayfinder.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte index 4f66351c9..e17e17340 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Nullable.svelte @@ -1,6 +1,6 @@ Page 1 diff --git a/packages/svelte5/test-app/Pages/Links/AsWarning.svelte b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte index dbc998c9e..19a44aefd 100644 --- a/packages/svelte5/test-app/Pages/Links/AsWarning.svelte +++ b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte index 0fd8eec12..b89391cfc 100644 --- a/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte +++ b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte b/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte index d8d2e2f45..bb175dafe 100644 --- a/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte +++ b/packages/svelte5/test-app/Pages/Links/AutomaticCancellation.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte index 37059c04c..002bbc9d7 100644 --- a/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte +++ b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte b/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte index 57247dcd7..66fe8dabc 100644 --- a/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte +++ b/packages/svelte5/test-app/Pages/Links/Data/AutoConverted.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/DataLoading.svelte b/packages/svelte5/test-app/Pages/Links/DataLoading.svelte index 3bb27b1e9..7c6b3aa50 100644 --- a/packages/svelte5/test-app/Pages/Links/DataLoading.svelte +++ b/packages/svelte5/test-app/Pages/Links/DataLoading.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/Headers.svelte b/packages/svelte5/test-app/Pages/Links/Headers.svelte index 29745fd93..d7874af8b 100644 --- a/packages/svelte5/test-app/Pages/Links/Headers.svelte +++ b/packages/svelte5/test-app/Pages/Links/Headers.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/Location.svelte b/packages/svelte5/test-app/Pages/Links/Location.svelte index 143064e13..bcd7503d0 100644 --- a/packages/svelte5/test-app/Pages/Links/Location.svelte +++ b/packages/svelte5/test-app/Pages/Links/Location.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/Method.svelte b/packages/svelte5/test-app/Pages/Links/Method.svelte index 889eff06e..077714235 100644 --- a/packages/svelte5/test-app/Pages/Links/Method.svelte +++ b/packages/svelte5/test-app/Pages/Links/Method.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte index 8809ba20b..f657f464a 100644 --- a/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte +++ b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte index 6cd928701..672db774e 100644 --- a/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte +++ b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte @@ -3,7 +3,7 @@
diff --git a/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte b/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte index b1d709f33..3c57eecc2 100644 --- a/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte +++ b/packages/svelte5/test-app/Pages/Links/UrlFragments.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte index bb2cc6463..f8d1f649e 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Nested/PageB.svelte @@ -12,7 +12,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte index 045849e49..6c19a0ad6 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageA.svelte @@ -9,7 +9,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte index a676aaf7f..340f84ed6 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/RenderFunction/Simple/PageB.svelte @@ -9,7 +9,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte index d97763b3e..848f9ba33 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte @@ -6,7 +6,7 @@ diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte index 655b7035f..88f3ffcaf 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte @@ -6,7 +6,7 @@ diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte index 6eb6f083b..0f36a7564 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte @@ -5,7 +5,7 @@ diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte index cdadd08bd..7393b8b42 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte @@ -5,7 +5,7 @@ diff --git a/packages/svelte5/test-app/Pages/Poll/Hook.svelte b/packages/svelte5/test-app/Pages/Poll/Hook.svelte index aa7488b30..636ed6b09 100644 --- a/packages/svelte5/test-app/Pages/Poll/Hook.svelte +++ b/packages/svelte5/test-app/Pages/Poll/Hook.svelte @@ -1,5 +1,5 @@
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte b/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte index fe63f6d2c..8d4ce3400 100644 --- a/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte +++ b/packages/svelte5/test-app/Pages/Prefetch/Wayfinder.svelte @@ -1,5 +1,5 @@ diff --git a/packages/svelte5/test-app/app.ts b/packages/svelte5/test-app/app.ts index 194f25397..216a92f20 100644 --- a/packages/svelte5/test-app/app.ts +++ b/packages/svelte5/test-app/app.ts @@ -1,4 +1,4 @@ -import { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte' +import { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte5' window.testing = { Inertia: router } diff --git a/packages/svelte5/test-app/package.json b/packages/svelte5/test-app/package.json index f988e796a..d2081b04f 100644 --- a/packages/svelte5/test-app/package.json +++ b/packages/svelte5/test-app/package.json @@ -16,6 +16,6 @@ }, "dependencies": { "@inertiajs/core": "workspace:*", - "@inertiajs/svelte": "workspace:*" + "@inertiajs/svelte5": "workspace:*" } } From 2cddcf52ea22a8cba501d3d992b5944417ca0c45 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:59:45 +1000 Subject: [PATCH 003/112] refactor(test-app): update to svelte5 page store usage Replace all usages of $page and @inertiajs/svelte imports with page and @inertiajs/svelte5 in test-app Svelte components. This aligns the test app with the new svelte5 API and ensures consistent usage of the page store and form helpers. --- .../test-app/Layouts/NestedLayout.svelte | 2 +- .../test-app/Layouts/SiteLayout.svelte | 2 +- packages/svelte5/test-app/Pages/Dump.svelte | 4 +- packages/svelte5/test-app/Pages/Events.svelte | 54 ++++---- .../test-app/Pages/FormHelper/Data.svelte | 38 +++--- .../test-app/Pages/FormHelper/Events.svelte | 126 +++++++++--------- packages/svelte5/test-app/Pages/Home.svelte | 4 +- .../Shorthand/Nested/PageA.svelte | 2 +- .../Shorthand/Nested/PageB.svelte | 2 +- .../Shorthand/Simple/PageA.svelte | 2 +- .../Shorthand/Simple/PageB.svelte | 2 +- .../test-app/Pages/Prefetch/Form.svelte | 6 +- .../Pages/Svelte/PropsAndPageStore.svelte | 12 +- .../Pages/Visits/PartialReloads.svelte | 2 +- 14 files changed, 129 insertions(+), 129 deletions(-) diff --git a/packages/svelte5/test-app/Layouts/NestedLayout.svelte b/packages/svelte5/test-app/Layouts/NestedLayout.svelte index 088fe7d5b..aa99a6cbc 100644 --- a/packages/svelte5/test-app/Layouts/NestedLayout.svelte +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -6,7 +6,7 @@ onMount(() => { window._inertia_nested_layout_id = crypto.randomUUID() - window._inertia_nested_layout_props = $page.props + window._inertia_nested_layout_props = page.props createdAt = Date.now() }) diff --git a/packages/svelte5/test-app/Layouts/SiteLayout.svelte b/packages/svelte5/test-app/Layouts/SiteLayout.svelte index de69a29ae..46dca6873 100644 --- a/packages/svelte5/test-app/Layouts/SiteLayout.svelte +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -6,7 +6,7 @@ onMount(() => { window._inertia_layout_id = crypto.randomUUID() - window._inertia_site_layout_props = $page.props + window._inertia_site_layout_props = page.props createdAt = Date.now() }) diff --git a/packages/svelte5/test-app/Pages/Dump.svelte b/packages/svelte5/test-app/Pages/Dump.svelte index 7f378d11e..feb9071e1 100644 --- a/packages/svelte5/test-app/Pages/Dump.svelte +++ b/packages/svelte5/test-app/Pages/Dump.svelte @@ -1,6 +1,6 @@
- {#if $form.errors.name} - {$form.errors.name} + {#if form.errors.name} + {form.errors.name} {/if} - {#if $form.errors.handle} - {$form.errors.handle} + {#if form.errors.handle} + {form.errors.handle} {/if} - {#if $form.errors.remember} - {$form.errors.remember} + {#if form.errors.remember} + {form.errors.remember} {/if} @@ -74,5 +74,5 @@ - Form has {$form.hasErrors ? '' : 'no '}errors + Form has {form.hasErrors ? '' : 'no '}errors
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Events.svelte b/packages/svelte5/test-app/Pages/FormHelper/Events.svelte index 15d5dae20..74b7d3b5e 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Events.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Events.svelte @@ -8,7 +8,7 @@ diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte index 848f9ba33..0cc356bfb 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte @@ -8,7 +8,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte index 88f3ffcaf..f4fc7f822 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte @@ -8,7 +8,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte index 0f36a7564..a45ab415c 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte @@ -7,7 +7,7 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte index 7393b8b42..9d2e99813 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte @@ -7,7 +7,7 @@
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Form.svelte b/packages/svelte5/test-app/Pages/Prefetch/Form.svelte index 639d7b877..83b442a82 100644 --- a/packages/svelte5/test-app/Pages/Prefetch/Form.svelte +++ b/packages/svelte5/test-app/Pages/Prefetch/Form.svelte @@ -4,17 +4,17 @@ const form = useForm({}) const submitToSame = () => { - $form.post('/prefetch/form') + form.post('/prefetch/form') } const submitToOther = () => { - $form.post('/prefetch/redirect-back') + form.post('/prefetch/redirect-back') }

- Random Value: {$page.props.randomValue} + Random Value: {page.props.randomValue}

diff --git a/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte b/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte index 6d164079f..a516e0b23 100644 --- a/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte +++ b/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte @@ -7,14 +7,14 @@ const form = useForm({ foo }) console.log('[script] foo prop is', foo) - console.log('[script] $page.props.foo is', $page.props.foo) + console.log('[script] page.props.foo is', page.props.foo) $: console.log('[reactive expression] foo prop is', foo) - $: console.log('[reactive expression] $page.props.foo is', $page.props.foo) + $: console.log('[reactive expression] page.props.foo is', page.props.foo) onMount(() => { console.log('[onMount] foo prop is', foo) - console.log('[onMount] $page.props.foo is', $page.props.foo) + console.log('[onMount] page.props.foo is', page.props.foo) }) type PageProps = { @@ -22,14 +22,14 @@ } const pageProps: PageProps = { - foo: $page.props.foo, + foo: page.props.foo, }
- +

foo prop is {foo}

-

$page.props.foo is {$page.props.foo}

+

page.props.foo is {page.props.foo}

pageProps.foo is {pageProps.foo}

Bar diff --git a/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte index 2923a3541..1ee8a0ec5 100644 --- a/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte +++ b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte @@ -8,7 +8,7 @@ export let headers onMount(() => { - window._inertia_props = $page.props + window._inertia_props = page.props }) const partialReloadVisit = () => { From 0a4ab02f5f84cb18fac530ce6584cb4565b5d40f Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:49:47 +1000 Subject: [PATCH 004/112] refactor(components): migrate to $props and $state Refactored Svelte components to use $props and $state for props and state management, replacing legacy export let syntax. Updated page state management to support both runes-based and store-based approaches for backward compatibility. Adjusted test-app usage to align with new $page and mount API. --- packages/svelte5/src/components/App.svelte | 14 ++--- .../svelte5/src/components/Deferred.svelte | 14 ++--- packages/svelte5/src/components/Link.svelte | 61 +++++++++++++------ packages/svelte5/src/components/Render.svelte | 24 +++++--- .../svelte5/src/components/WhenVisible.svelte | 28 ++++++--- packages/svelte5/src/page.svelte.ts | 41 +++++++++++++ packages/svelte5/src/page.ts | 15 +---- .../Pages/ClientSideVisit/Page2.svelte | 2 +- packages/svelte5/test-app/Pages/Home.svelte | 2 +- packages/svelte5/test-app/app.ts | 3 +- 10 files changed, 131 insertions(+), 73 deletions(-) create mode 100644 packages/svelte5/src/page.svelte.ts diff --git a/packages/svelte5/src/components/App.svelte b/packages/svelte5/src/components/App.svelte index df454db00..68043e6ae 100644 --- a/packages/svelte5/src/components/App.svelte +++ b/packages/svelte5/src/components/App.svelte @@ -1,4 +1,4 @@ - @@ -56,7 +77,7 @@ cacheFor, cacheTags, }} - {...$$restProps} + {...restProps} {...elProps} on:focus on:blur diff --git a/packages/svelte5/src/components/Render.svelte b/packages/svelte5/src/components/Render.svelte index 895dec332..b31c48712 100644 --- a/packages/svelte5/src/components/Render.svelte +++ b/packages/svelte5/src/components/Render.svelte @@ -1,4 +1,4 @@ - {#if component} @@ -50,13 +54,15 @@ while the layout components are persisted across page changes. --> {#key children?.length === 0 ? key : null} {#if children.length > 0} - + {@const Component = component} + {#each children as child} - + {/each} - + {:else} - + {@const Component = component} + {/if} {/key} {/if} diff --git a/packages/svelte5/src/components/WhenVisible.svelte b/packages/svelte5/src/components/WhenVisible.svelte index dbd39bc26..fbdd66639 100644 --- a/packages/svelte5/src/components/WhenVisible.svelte +++ b/packages/svelte5/src/components/WhenVisible.svelte @@ -2,16 +2,24 @@ import { router, type ReloadOptions } from '@inertiajs/core' import { onDestroy, onMount } from 'svelte' - export let data: string | string[] = '' - export let params: ReloadOptions = {} - export let buffer: number = 0 - export let as: keyof HTMLElementTagNameMap = 'div' - export let always: boolean = false - - let loaded = false - let fetching = false - let el: HTMLElement - let observer: IntersectionObserver | null = null + const { + data = '', + params = {}, + buffer = 0, + as = 'div', + always = false + }: { + data?: string | string[] + params?: ReloadOptions + buffer?: number + as?: keyof HTMLElementTagNameMap + always?: boolean + } = $props() + + let loaded = $state(false) + let fetching = $state(false) + let el = $state() + let observer = $state(null) onMount(() => { if (!el) { diff --git a/packages/svelte5/src/page.svelte.ts b/packages/svelte5/src/page.svelte.ts new file mode 100644 index 000000000..4fe3a8ded --- /dev/null +++ b/packages/svelte5/src/page.svelte.ts @@ -0,0 +1,41 @@ +import { type Page } from '@inertiajs/core' +import { writable } from 'svelte/store' + +type SveltePage = Omit & { + props: Page['props'] & { + [key: string]: any + } +} + +// Create both runes-based state AND store-based state for backward compatibility +export const pageState = $state({ + component: '', + props: {}, + url: '', + version: '' +} as SveltePage) + +// Create a Svelte store for backward compatibility with $page syntax +const { set: setPageStore, subscribe } = writable(pageState) + +export const setPage = (newPage: SveltePage) => { + // Update the runes-based state (only mutate properties) + pageState.component = newPage.component + pageState.props = newPage.props + pageState.url = newPage.url + pageState.version = newPage.version + + // Copy any additional properties + Object.keys(newPage).forEach(key => { + if (key !== 'component' && key !== 'props' && key !== 'url' && key !== 'version') { + ;(pageState as any)[key] = (newPage as any)[key] + } + }) + + // Also update the store for backward compatibility + setPageStore(pageState) +} + +// Export the runes-based state as pageState for new components +// Export a store-compatible object as default for backward compatibility +export const page = { subscribe } diff --git a/packages/svelte5/src/page.ts b/packages/svelte5/src/page.ts index 9480306b7..ed08fecd3 100644 --- a/packages/svelte5/src/page.ts +++ b/packages/svelte5/src/page.ts @@ -1,14 +1 @@ -import { type Page } from '@inertiajs/core' -import { writable } from 'svelte/store' - -type SveltePage = Omit & { - props: Page['props'] & { - [key: string]: any - } -} - -const { set, subscribe } = writable() - -export const setPage = set - -export default { subscribe } +export { page as default, setPage } from './page.svelte' diff --git a/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte b/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte index 6e8277280..4184aef83 100644 --- a/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte +++ b/packages/svelte5/test-app/Pages/ClientSideVisit/Page2.svelte @@ -1,5 +1,5 @@
{baz}
diff --git a/packages/svelte5/test-app/Pages/Home.svelte b/packages/svelte5/test-app/Pages/Home.svelte index 2625583ed..1b3943dbf 100644 --- a/packages/svelte5/test-app/Pages/Home.svelte +++ b/packages/svelte5/test-app/Pages/Home.svelte @@ -20,7 +20,7 @@ onMount(() => { window._inertia_page_key = crypto.randomUUID() - window._inertia_props = page.props + window._inertia_props = $page.props window._plugin_global_props = {} }) diff --git a/packages/svelte5/test-app/app.ts b/packages/svelte5/test-app/app.ts index 216a92f20..fed786a08 100644 --- a/packages/svelte5/test-app/app.ts +++ b/packages/svelte5/test-app/app.ts @@ -1,4 +1,5 @@ import { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte5' +import { mount } from 'svelte' window.testing = { Inertia: router } @@ -16,6 +17,6 @@ createInertiaApp({ return pages[`./Pages/${name}.svelte`] }, setup({ el, App, props }) { - new App({ target: el!, props }) + return mount(App as any, { target: el!, props }) }, }) From 2c77cc90ef776937982986ef210b51d20078a953 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:01:54 +1000 Subject: [PATCH 005/112] refactor(components): switch to children/fallback props Refactors Deferred, Form, Link, and WhenVisible components to use `children` and `fallback` props instead of Svelte slots. This improves composability and aligns with a more functional component API. --- .../svelte5/src/components/Deferred.svelte | 22 ++-- packages/svelte5/src/components/Form.svelte | 108 +++++++++++------- packages/svelte5/src/components/Link.svelte | 4 +- .../svelte5/src/components/WhenVisible.svelte | 12 +- 4 files changed, 92 insertions(+), 54 deletions(-) diff --git a/packages/svelte5/src/components/Deferred.svelte b/packages/svelte5/src/components/Deferred.svelte index f1d20da6f..11c132454 100644 --- a/packages/svelte5/src/components/Deferred.svelte +++ b/packages/svelte5/src/components/Deferred.svelte @@ -1,7 +1,11 @@ {#if loaded} - + {@render children?.()} {:else} - + {@render fallback?.()} {/if} diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte index 194e4cf1e..01168981e 100644 --- a/packages/svelte5/src/components/Form.svelte +++ b/packages/svelte5/src/components/Form.svelte @@ -15,28 +15,57 @@ const noop = () => undefined - export let action: FormComponentProps['action'] = '' - export let method: FormComponentProps['method'] = 'get' - export let headers: FormComponentProps['headers'] = {} - export let queryStringArrayFormat: FormComponentProps['queryStringArrayFormat'] = 'brackets' - export let errorBag: FormComponentProps['errorBag'] = null - export let showProgress: FormComponentProps['showProgress'] = true - export let transform: FormComponentProps['transform'] = (data) => data - export let options: FormComponentProps['options'] = {} - export let onCancelToken: FormComponentProps['onCancelToken'] = noop - export let onBefore: FormComponentProps['onBefore'] = noop - export let onStart: FormComponentProps['onStart'] = noop - export let onProgress: FormComponentProps['onProgress'] = noop - export let onFinish: FormComponentProps['onFinish'] = noop - export let onCancel: FormComponentProps['onCancel'] = noop - export let onSuccess: FormComponentProps['onSuccess'] = noop - export let onError: FormComponentProps['onError'] = noop - export let onSubmitComplete: FormComponentProps['onSubmitComplete'] = noop - export let disableWhileProcessing: boolean = false - export let invalidateCacheTags: FormComponentProps['invalidateCacheTags'] = [] - export let resetOnError: FormComponentProps['resetOnError'] = false - export let resetOnSuccess: FormComponentProps['resetOnSuccess'] = false - export let setDefaultsOnSuccess: FormComponentProps['setDefaultsOnSuccess'] = false + const { + action = '', + method = 'get', + headers = {}, + queryStringArrayFormat = 'brackets', + errorBag = null, + showProgress = true, + transform = (data) => data, + options = {}, + onCancelToken = noop, + onBefore = noop, + onStart = noop, + onProgress = noop, + onFinish = noop, + onCancel = noop, + onSuccess = noop, + onError = noop, + onSubmitComplete = noop, + disableWhileProcessing = false, + invalidateCacheTags = [], + resetOnError = false, + resetOnSuccess = false, + setDefaultsOnSuccess = false, + children, + ...restProps + }: { + action?: FormComponentProps['action'] + method?: FormComponentProps['method'] + headers?: FormComponentProps['headers'] + queryStringArrayFormat?: FormComponentProps['queryStringArrayFormat'] + errorBag?: FormComponentProps['errorBag'] + showProgress?: FormComponentProps['showProgress'] + transform?: FormComponentProps['transform'] + options?: FormComponentProps['options'] + onCancelToken?: FormComponentProps['onCancelToken'] + onBefore?: FormComponentProps['onBefore'] + onStart?: FormComponentProps['onStart'] + onProgress?: FormComponentProps['onProgress'] + onFinish?: FormComponentProps['onFinish'] + onCancel?: FormComponentProps['onCancel'] + onSuccess?: FormComponentProps['onSuccess'] + onError?: FormComponentProps['onError'] + onSubmitComplete?: FormComponentProps['onSubmitComplete'] + disableWhileProcessing?: boolean + invalidateCacheTags?: FormComponentProps['invalidateCacheTags'] + resetOnError?: FormComponentProps['resetOnError'] + resetOnSuccess?: FormComponentProps['resetOnSuccess'] + setDefaultsOnSuccess?: FormComponentProps['setDefaultsOnSuccess'] + children?: any + [key: string]: any + } = $props() type FormSubmitOptions = Omit @@ -45,8 +74,8 @@ let isDirty = false let defaultData: FormData = new FormData() - $: _method = isUrlMethodPair(action) ? action.method : (method.toLowerCase() as FormComponentProps['method']) - $: _action = isUrlMethodPair(action) ? action.url : action + const _method = $derived(isUrlMethodPair(action) ? action.method : (method.toLowerCase() as FormComponentProps['method'])) + const _action = $derived(isUrlMethodPair(action) ? action.url : action) function getFormData(): FormData { return new FormData(formElement) @@ -172,7 +201,7 @@ formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState)) } }) - $: slotErrors = $form.errors as Errors + const slotErrors = $derived($form.errors as Errors) - + {@render children?.({ + errors: slotErrors, + hasErrors: $form.hasErrors, + processing: $form.processing, + progress: $form.progress, + wasSuccessful: $form.wasSuccessful, + recentlySuccessful: $form.recentlySuccessful, + clearErrors, + reset, + defaults, + submit, + data: $form + })} diff --git a/packages/svelte5/src/components/Link.svelte b/packages/svelte5/src/components/Link.svelte index 0aac24af4..f710b88cc 100644 --- a/packages/svelte5/src/components/Link.svelte +++ b/packages/svelte5/src/components/Link.svelte @@ -26,6 +26,7 @@ prefetch = false, cacheFor = 0, cacheTags = [], + children, ...restProps }: { href?: string | UrlMethodPair @@ -43,6 +44,7 @@ prefetch?: boolean | LinkPrefetchOption | LinkPrefetchOption[] cacheFor?: CacheForOption | CacheForOption[] cacheTags?: string | string[] + children?: any [key: string]: any } = $props() @@ -99,5 +101,5 @@ on:prefetching on:prefetched > - + {@render children?.()} diff --git a/packages/svelte5/src/components/WhenVisible.svelte b/packages/svelte5/src/components/WhenVisible.svelte index fbdd66639..1d591daf6 100644 --- a/packages/svelte5/src/components/WhenVisible.svelte +++ b/packages/svelte5/src/components/WhenVisible.svelte @@ -7,13 +7,17 @@ params = {}, buffer = 0, as = 'div', - always = false + always = false, + children, + fallback }: { data?: string | string[] params?: ReloadOptions buffer?: number as?: keyof HTMLElementTagNameMap always?: boolean + children?: any + fallback?: any } = $props() let loaded = $state(false) @@ -89,7 +93,7 @@ {/if} {#if loaded} - -{:else if $$slots.fallback} - + {@render children?.()} +{:else if fallback} + {@render fallback?.()} {/if} From 9fd8b753e20fe22da1087dd866e5924ac23da8e2 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:10:16 +1000 Subject: [PATCH 006/112] refactor(deferred-props): update fallback syntax Replace usage of slot-based fallback fragments with the new {#snippet fallback()} syntax in Deferred components across InstantReload, ManyGroups, Page1, and Page2 Svelte files. This aligns with updated Svelte syntax for defining fallback content. --- .../Pages/DeferredProps/InstantReload.svelte | 12 ++++---- .../Pages/DeferredProps/ManyGroups.svelte | 30 +++++++++---------- .../test-app/Pages/DeferredProps/Page1.svelte | 12 ++++---- .../test-app/Pages/DeferredProps/Page2.svelte | 12 ++++++-- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte b/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte index 72bf3c809..73aef21eb 100644 --- a/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte +++ b/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte @@ -13,15 +13,15 @@ - -
Loading foo...
-
{foo?.text}
+ {#snippet fallback()} +
Loading foo...
+ {/snippet}
- -
Loading bar...
-
{bar?.text}
+ {#snippet fallback()} +
Loading bar...
+ {/snippet}
diff --git a/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte b/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte index da4a19479..31d4f37e4 100644 --- a/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte +++ b/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte @@ -9,38 +9,38 @@ - -
Loading foo...
-
{foo?.text} + {#snippet fallback()} +
Loading foo...
+ {/snippet}
- -
Loading bar...
-
{bar?.text} + {#snippet fallback()} +
Loading bar...
+ {/snippet}
- -
Loading baz...
-
{baz?.text} + {#snippet fallback()} +
Loading baz...
+ {/snippet}
- -
Loading qux...
-
{qux?.text} + {#snippet fallback()} +
Loading qux...
+ {/snippet}
- -
Loading quux...
-
{quux?.text} + {#snippet fallback()} +
Loading quux...
+ {/snippet}
Page 1 diff --git a/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte index 7809cb321..a159ffa1c 100644 --- a/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte @@ -6,17 +6,17 @@ - -
Loading foo...
-
{foo?.text} + {#snippet fallback()} +
Loading foo...
+ {/snippet}
- -
Loading bar...
-
{bar?.text} + {#snippet fallback()} +
Loading bar...
+ {/snippet}
Page 1 diff --git a/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte b/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte index f30be76d8..66ddb0abb 100644 --- a/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte @@ -6,16 +6,22 @@ -
Loading baz...
{baz} + {#snippet fallback()} +
Loading baz...
+ {/snippet}
-
Loading qux...
{qux} + {#snippet fallback()} +
Loading qux...
+ {/snippet}
-
Loading baz and qux...
both {baz} and {qux} + {#snippet fallback()} +
Loading baz and qux...
+ {/snippet}
From 05f05d8a1e7aafe5be1c2f9ab76e0d5d83d2aa95 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:16:20 +1000 Subject: [PATCH 007/112] refactor(events): use $page.url instead of page.url Replace all instances of page.url with $page.url in Events.svelte to ensure correct reactive referencing of the page URL. This change improves consistency and leverages Svelte's store syntax for reactivity. --- packages/svelte5/test-app/Pages/Events.svelte | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/svelte5/test-app/Pages/Events.svelte b/packages/svelte5/test-app/Pages/Events.svelte index 07072c549..bf6ff236f 100644 --- a/packages/svelte5/test-app/Pages/Events.svelte +++ b/packages/svelte5/test-app/Pages/Events.svelte @@ -20,7 +20,7 @@ } const withoutEventListeners = () => { - router.post(page.url, {}) + router.post($page.url, {}) } const removeInertiaListener = () => { @@ -30,7 +30,7 @@ removeEventListener() router.post( - page.url, + $page.url, {}, { onBefore: () => internalAlert('onBefore'), @@ -51,7 +51,7 @@ }) router.post( - page.url, + $page.url, {}, { onBefore: (event) => { @@ -68,7 +68,7 @@ router.on('before', () => internalAlert('Inertia.on(before)')) router.post( - page.url, + $page.url, {}, { onBefore: () => { @@ -88,7 +88,7 @@ }) router.post( - page.url, + $page.url, {}, { onBefore: () => internalAlert('onBefore'), @@ -105,7 +105,7 @@ }) router.post( - page.url, + $page.url, {}, { onBefore: () => internalAlert('onBefore'), @@ -120,7 +120,7 @@ document.addEventListener('inertia:cancelToken', () => internalAlert('This listener should not have been called.')) router.post( - page.url, + $page.url, {}, { onCancelToken: (event) => { @@ -143,7 +143,7 @@ }) router.post( - page.url, + $page.url, {}, { onStart: (event) => { @@ -165,7 +165,7 @@ internalAlert(event) }) - router.post(page.url, payloadWithFile, { + router.post($page.url, payloadWithFile, { onProgress: (event) => { internalAlert('onProgress') internalAlert(event) @@ -185,7 +185,7 @@ }) router.post( - page.url, + $page.url, {}, { onBefore: () => internalAlert('progressNoFilesOnBefore'), @@ -209,7 +209,7 @@ }) router.post( - page.url, + $page.url, {}, { onCancelToken: (token) => { @@ -271,7 +271,7 @@ }) router.post( - page.url, + $page.url, {}, { onError: () => internalAlert('This listener should not have been called'), @@ -285,7 +285,7 @@ const successPromiseVisit = () => { router.post( - page.url, + $page.url, {}, { onSuccess: () => callbackSuccessErrorPromise('onSuccess'), @@ -307,7 +307,7 @@ }) router.post( - page.url, + $page.url, {}, { onFinish: (event) => { @@ -422,7 +422,7 @@ } const lifecycleSuccess = () => { - router.post(page.url, payloadWithFile, registerAllListeners()) + router.post($page.url, payloadWithFile, registerAllListeners()) } const lifecycleError = () => { @@ -446,7 +446,7 @@ const lifecycleCancelAfterFinish = () => { let cancelToken: { cancel: () => void } | null = null - router.post(page.url, payloadWithFile, { + router.post($page.url, payloadWithFile, { ...registerAllListeners(), onCancelToken: (token) => { internalAlert('onCancelToken') @@ -498,13 +498,13 @@ Before Event (Prevent) @@ -532,7 +532,7 @@ Cancel Event Start Event @@ -552,12 +552,12 @@ >Missing Progress Event (no files) Success Event (delaying onFinish w/ Promise) From 6815b1b4ce0df20004d15096374dc8820b454393 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:19:59 +1000 Subject: [PATCH 008/112] refactor(FormComponent): use snippet for children Refactor FormComponent to wrap form elements in a snippet block using the children({ isDirty }) pattern instead of let:isDirty. This improves consistency with the updated API and enhances readability. --- .../Pages/FormComponent/Elements.svelte | 212 +++++++++--------- 1 file changed, 107 insertions(+), 105 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte index 2c32b7000..e2ce52797 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte @@ -2,109 +2,111 @@ import { Form } from '@inertiajs/svelte5' -
-

Form Elements

- -
- Form is {isDirty ? 'dirty' : 'clean'} -
- - -
- -
- - -
- -
- - -
- -
- - -
- - - -
- - -
- - -
- - -
- - - -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- - -
- - -
- -
- - - + + {#snippet children({ isDirty })} +

Form Elements

+ +
+ Form is {isDirty ? 'dirty' : 'clean'} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ + + + {/snippet}
From 6b346fc6bad1b05712e8d3028b1e9e1bcaaac4a9 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:23:54 +1000 Subject: [PATCH 009/112] refactor(Deferred): improve reactivity in effect Access pageState.props within the $effect callback to ensure proper reactivity. Assign props to a local variable and use it for loaded state calculation. --- packages/svelte5/src/components/Deferred.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/svelte5/src/components/Deferred.svelte b/packages/svelte5/src/components/Deferred.svelte index 11c132454..5bf057c45 100644 --- a/packages/svelte5/src/components/Deferred.svelte +++ b/packages/svelte5/src/components/Deferred.svelte @@ -15,9 +15,13 @@ if (!isServer) { // Use $effect to watch for changes in pageState.props $effect(() => { + // Access pageState.props to make this effect reactive + const props = pageState.props + // Ensures the content isn't loaded before the deferred props are available window.queueMicrotask(() => { - loaded = keys.every((key) => typeof pageState.props[key] !== 'undefined') + const newLoaded = keys.every((key) => typeof props[key] !== 'undefined') + loaded = newLoaded }) }) } From d12b8575b0c0673b6299992e60d36de4640ecae4 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:24:29 +1000 Subject: [PATCH 010/112] refactor(App): improve page state reactivity Replace $state with $derived for renderProps to ensure reactive updates. Move setPage(page) into an $effect to synchronize global page state with local changes. Cleans up redundant assignments in event handler. --- packages/svelte5/src/components/App.svelte | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/svelte5/src/components/App.svelte b/packages/svelte5/src/components/App.svelte index 68043e6ae..70aaf97fb 100644 --- a/packages/svelte5/src/components/App.svelte +++ b/packages/svelte5/src/components/App.svelte @@ -20,9 +20,12 @@ let component = $state(initialComponent) let key = $state(null) let page = $state(initialPage) - let renderProps = $state(resolveRenderProps(component, page, key)) + let renderProps = $derived(resolveRenderProps(component, page, key)) - setPage(page) + // Reactively update the global page state when local page state changes + $effect(() => { + setPage(page) + }) const isServer = typeof window === 'undefined' @@ -34,9 +37,6 @@ component = args.component as ResolvedComponent page = args.page key = args.preserveState ? key : Date.now() - - renderProps = resolveRenderProps(component, page, key) - setPage(page) }, }) } From fd1f17793dbe29b4a2958fee0cda84d5ba29b4eb Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:26:52 +1000 Subject: [PATCH 011/112] refactor(FormComponent): wrap form content in snippet Refactor Errors.svelte to wrap form content in a snippet block using children({ errors, hasErrors, setError, clearErrors }). This improves composability and makes the form logic more reusable. --- .../Pages/FormComponent/Errors.svelte | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte index 8a2108920..b27115a57 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte @@ -8,46 +8,44 @@ action={errorBag ? '/form-component/errors/bag' : '/form-component/errors'} method="post" {errorBag} - let:errors - let:hasErrors - let:setError - let:clearErrors > -

Form Errors

+ {#snippet children({ errors, hasErrors, setError, clearErrors })} +

Form Errors

- {#if hasErrors} -
Form has errors
- {:else} -
No errors
- {/if} + {#if hasErrors} +
Form has errors
+ {:else} +
No errors
+ {/if} -
- - -
{errors.name || ''}
-
+
+ + +
{errors.name || ''}
+
-
- - -
{errors.handle || ''}
-
+
+ + +
{errors.handle || ''}
+
-
- - - - -
+
+ + + + +
- + + {/snippet} From ec49202c4ee5c7a562af1a3e111ea282d1cd7dfc Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:40:51 +1000 Subject: [PATCH 012/112] refactor(components): update event handler syntax Refactor Form and Link components to use direct event handler props instead of Svelte's on:event syntax. This improves compatibility with Svelte 5 and enables more flexible event handling. --- packages/svelte5/src/components/Form.svelte | 4 +- packages/svelte5/src/components/Link.svelte | 78 ++++++++++++++++----- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte index 01168981e..500d1b5af 100644 --- a/packages/svelte5/src/components/Form.svelte +++ b/packages/svelte5/src/components/Form.svelte @@ -208,8 +208,8 @@ bind:this={formElement} action={_action} method={_method} - on:submit={handleSubmit} - on:reset={handleReset} + onsubmit={handleSubmit} + onreset={handleReset} {...restProps} inert={disableWhileProcessing && $form.processing ? true : undefined} > diff --git a/packages/svelte5/src/components/Link.svelte b/packages/svelte5/src/components/Link.svelte index f710b88cc..3721f702a 100644 --- a/packages/svelte5/src/components/Link.svelte +++ b/packages/svelte5/src/components/Link.svelte @@ -27,6 +27,26 @@ cacheFor = 0, cacheTags = [], children, + // Extract event handlers with new Svelte 5 syntax + onfocus, + onblur, + onclick, + ondblclick, + onmousedown, + onmousemove, + onmouseout, + onmouseover, + onmouseup, + onbefore, + onstart, + onprogress, + onfinish, + oncancel, + onsuccess, + onerror, + onprefetching, + onprefetched, + 'oncancel-token': oncanceltoken, ...restProps }: { href?: string | UrlMethodPair @@ -45,6 +65,26 @@ cacheFor?: CacheForOption | CacheForOption[] cacheTags?: string | string[] children?: any + // Event handler types + onfocus?: (event: FocusEvent) => void + onblur?: (event: FocusEvent) => void + onclick?: (event: MouseEvent) => void + ondblclick?: (event: MouseEvent) => void + onmousedown?: (event: MouseEvent) => void + onmousemove?: (event: MouseEvent) => void + onmouseout?: (event: MouseEvent) => void + onmouseover?: (event: MouseEvent) => void + onmouseup?: (event: MouseEvent) => void + onbefore?: (event: any) => void + onstart?: (event: any) => void + onprogress?: (event: any) => void + onfinish?: (event: any) => void + oncancel?: (event: any) => void + onsuccess?: (event: any) => void + onerror?: (event: any) => void + onprefetching?: (event: any) => void + onprefetched?: (event: any) => void + 'oncancel-token'?: (event: any) => void [key: string]: any } = $props() @@ -81,25 +121,25 @@ }} {...restProps} {...elProps} - on:focus - on:blur - on:click - on:dblclick - on:mousedown - on:mousemove - on:mouseout - on:mouseover - on:mouseup - on:cancel-token - on:before - on:start - on:progress - on:finish - on:cancel - on:success - on:error - on:prefetching - on:prefetched + {onfocus} + {onblur} + {onclick} + {ondblclick} + {onmousedown} + {onmousemove} + {onmouseout} + {onmouseover} + {onmouseup} + oncancel-token={oncanceltoken} + {onbefore} + {onstart} + {onprogress} + {onfinish} + {oncancel} + {onsuccess} + {onerror} + {onprefetching} + {onprefetched} > {@render children?.()} From c89142481f9ad4497379ae166adb11d6946d86aa Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:48:22 +1000 Subject: [PATCH 013/112] feat(form): expose isDirty and setError in Form Expose isDirty and setError from the Form component to consumers. Update SetDefaultsOnSuccess example to use the new children snippet API for accessing isDirty and errors. --- packages/svelte5/src/components/Form.svelte | 4 ++- .../FormComponent/SetDefaultsOnSuccess.svelte | 28 ++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte index 500d1b5af..215eb4cf7 100644 --- a/packages/svelte5/src/components/Form.svelte +++ b/packages/svelte5/src/components/Form.svelte @@ -71,7 +71,7 @@ const form = useForm({}) let formElement: HTMLFormElement - let isDirty = false + let isDirty = $state(false) let defaultData: FormData = new FormData() const _method = $derived(isUrlMethodPair(action) ? action.method : (method.toLowerCase() as FormComponentProps['method'])) @@ -220,7 +220,9 @@ progress: $form.progress, wasSuccessful: $form.wasSuccessful, recentlySuccessful: $form.recentlySuccessful, + isDirty, clearErrors, + setError, reset, defaults, submit, diff --git a/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte index 7dde16296..2fa38549e 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte @@ -2,20 +2,22 @@ import { Form } from '@inertiajs/svelte5' -
-

{isDirty ? 'Form is dirty' : 'Form is clean'}

+ + {#snippet children({ isDirty, errors })} +

{isDirty ? 'Form is dirty' : 'Form is clean'}

-
- - -

{errors.name || ''}

-
+
+ + +

{errors.name || ''}

+
-
- - -

{errors.email || ''}

-
+
+ + +

{errors.email || ''}

+
- + + {/snippet}
From f353ab4427146a6884bf68bb8665390c40f21546 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:50:30 +1000 Subject: [PATCH 014/112] refactor(form): update Form usage to snippet block Refactor ResetOnError and ResetOnSuccess components to use the {#snippet children({ errors })} block instead of let:errors. This aligns with updated Form API usage and improves code consistency. --- .../ResetAttributes/ResetOnError.svelte | 26 ++++++++++--------- .../ResetAttributes/ResetOnSuccess.svelte | 26 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte index b6f93cd51..d883d0eed 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte @@ -2,18 +2,20 @@ import { Form } from '@inertiajs/svelte5' -
-
- - -

{errors.name || ''}

-
+ + {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
-
- - -

{errors.email || ''}

-
+
+ + +

{errors.email || ''}

+
- + + {/snippet}
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte index 84530b4ba..73dadab25 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte @@ -2,18 +2,20 @@ import { Form } from '@inertiajs/svelte5' -
-
- - -

{errors.name || ''}

-
+ + {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
-
- - -

{errors.email || ''}

-
+
+ + +

{errors.email || ''}

+
- + + {/snippet}
From b322570f34f10ec26de76136d71d08b59c901c81 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:54:01 +1000 Subject: [PATCH 015/112] refactor(form): update Form usage to snippet block Refactor ResetOnErrorFields and ResetOnSuccessFields components to use the {#snippet children({ errors })} block instead of let:errors. This aligns with updated Form API usage and improves code consistency. --- .../ResetAttributes/ResetOnErrorFields.svelte | 26 ++++++++++--------- .../ResetOnSuccessFields.svelte | 26 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte index da5d6a291..f4d4471d8 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte @@ -2,18 +2,20 @@ import { Form } from '@inertiajs/svelte5' -
-
- - -

{errors.name || ''}

-
+ + {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
-
- - -

{errors.email || ''}

-
+
+ + +

{errors.email || ''}

+
- + + {/snippet}
diff --git a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte index 314636cb1..a7f0256dd 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte @@ -2,18 +2,20 @@ import { Form } from '@inertiajs/svelte5' -
-
- - -

{errors.name || ''}

-
+ + {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
-
- - -

{errors.email || ''}

-
+
+ + +

{errors.email || ''}

+
- + + {/snippet}
From 232103a0a3b111d28f565228b4744cf0b06fcf2f Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:54:15 +1000 Subject: [PATCH 016/112] refactor(FormComponent): update slot usage Replace manual slot props with snippet block for children, improving readability and maintainability of form event state handling. --- packages/svelte5/test-app/Pages/FormComponent/Events.svelte | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/Events.svelte b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte index 57fb50d7d..9813236bf 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Events.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte @@ -80,11 +80,8 @@ {onSuccess} {onError} {onCancelToken} - let:processing - let:progress - let:wasSuccessful - let:recentlySuccessful > + {#snippet children({ processing, progress, wasSuccessful, recentlySuccessful })}

Form Events & State

@@ -120,4 +117,5 @@
+ {/snippet} From acf60660855f5749e0b9c500536cf0a41285f907 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:56:19 +1000 Subject: [PATCH 017/112] refactor(form): update Form usage and error display Refactor Form component usage to use 'action' instead of 'bind:action' and implement the 'children' snippet for rendering form fields. Change error message container from

to

for consistency. --- .../DisableWhileProcessing.svelte | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte index 908b43b90..4e447d0e2 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte @@ -7,16 +7,16 @@

Form Disable While Processing Test

-
-
- - {#if errors.name} -

{errors.name}

- {/if} -
+ + {#snippet children({ errors })} +
+ + {#if errors.name} +
{errors.name}
+ {/if} +
-
-
+ {/snippet}
From 9e911e1315c1d970bae123de838b211608af0bda Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Tue, 23 Sep 2025 23:59:17 +1000 Subject: [PATCH 018/112] refactor(FormComponent): update Form usage Refactor EmptyAction.svelte to use the snippet block for children and remove the let:errors directive. Error messages are now rendered inside a div instead of a paragraph. --- .../Pages/FormComponent/EmptyAction.svelte | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte index ef8997114..ba4758f24 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte @@ -5,16 +5,16 @@

Form Empty Action Test

-
-
- - {#if errors.name} -

{errors.name}

- {/if} -
+ + {#snippet children({ errors })} +
+ + {#if errors.name} +
{errors.name}
+ {/if} +
-
-
+ {/snippet}
From 935b9174902a07f188767d77932b2ac88e8f6723 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:03:09 +1000 Subject: [PATCH 019/112] feat(FormComponent): add email field to form Introduce an email input field to the form and update error handling to support both name and email fields. Refactor markup to use snippet block for children and improve error display. --- .../SubmitComplete/Redirect.svelte | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte index f79d1e86e..152264cee 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte @@ -5,16 +5,24 @@

Form Empty Action Test

-
props.reset('name')}> -
- - {#if errors.name} -

{errors.name}

- {/if} -
+ props.reset('name')}> + {#snippet children({ errors })} +
+ + {#if errors.name} +
{errors.name}
+ {/if} +
+ +
+ + + {#if errors.email} +
{errors.email}
+ {/if} +
-
-
+ {/snippet}
From 8337de17ee356e308afc3c6e6e3caeedc0506055 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 00:12:24 +1000 Subject: [PATCH 020/112] test(svelte): skip tests for svelte5 adapter Update test.skip conditions to also skip tests when PACKAGE is 'svelte5', reflecting lack of support for Head and Link features in the Svelte 5 adapter. --- tests/head.spec.ts | 2 +- tests/links.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/head.spec.ts b/tests/head.spec.ts index 7552ba80b..c01a017a3 100644 --- a/tests/head.spec.ts +++ b/tests/head.spec.ts @@ -1,7 +1,7 @@ import { expect, test } from '@playwright/test' test('renders the title tag and children', async ({ page }) => { - test.skip(process.env.PACKAGE === 'svelte', 'Svelte adapter has no Head component') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Svelte adapter has no Head component') await page.goto('/head') diff --git a/tests/links.spec.ts b/tests/links.spec.ts index 3fdae6b10..345ada78f 100644 --- a/tests/links.spec.ts +++ b/tests/links.spec.ts @@ -821,7 +821,7 @@ test.describe('"as" attribute', () => { }) test.describe('as component', () => { - test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Feature not supported by the Svelte adapter') test.beforeEach(async ({ page }) => { await page.goto('/links/as-component/1') @@ -898,7 +898,7 @@ test.describe('as component', () => { }) test.describe('as element', () => { - test.skip(process.env.PACKAGE === 'svelte', 'Feature not supported by the Svelte adapter') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Feature not supported by the Svelte adapter') test.beforeEach(async ({ page }) => { await page.goto('/links/as-element/1') From 073f47ff896f0877010d9a9ef7462efb6c70c2b6 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 08:31:02 +1000 Subject: [PATCH 021/112] refactor(form): migrate useForm to Svelte runes Replaces the store-based useForm implementation with a Svelte runes-based version for improved reactivity and integration. Updates all imports and usage to reference the new useForm.svelte.ts, removes the old useForm.ts, and adjusts related components and test apps accordingly. --- packages/svelte5/src/components/Form.svelte | 31 +- packages/svelte5/src/index.ts | 2 +- packages/svelte5/src/useForm.svelte.ts | 315 ++++++++++++++++++ packages/svelte5/src/useForm.ts | 290 ---------------- .../Pages/FormComponent/Elements.svelte | 2 +- .../test-app/Pages/FormHelper/Data.svelte | 2 +- 6 files changed, 332 insertions(+), 310 deletions(-) create mode 100644 packages/svelte5/src/useForm.svelte.ts delete mode 100644 packages/svelte5/src/useForm.ts diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte index 215eb4cf7..bebdeba5a 100644 --- a/packages/svelte5/src/components/Form.svelte +++ b/packages/svelte5/src/components/Form.svelte @@ -11,7 +11,7 @@ } from '@inertiajs/core' import { isEqual } from 'lodash-es' import { onMount } from 'svelte' - import useForm from '../useForm' + import useForm from '../useForm.svelte' const noop = () => undefined @@ -146,7 +146,7 @@ ...options, } - $form.transform(() => transform(_data)).submit(_method, url, submitOptions) + form.transform(() => transform(_data)).submit(_method, url, submitOptions) } function handleSubmit(event: Event) { @@ -167,22 +167,19 @@ } export function clearErrors(...fields: string[]) { - // @ts-expect-error - $form.clearErrors(...fields) + form.clearErrors(...fields) } export function resetAndClearErrors(...fields: string[]) { - // @ts-expect-error - $form.clearErrors(...fields) + form.clearErrors(...fields) reset(...fields) } export function setError(field: string | object, value?: string) { if (typeof field === 'string') { - // @ts-expect-error - $form.setError(field, value) + form.setError(field, value) } else { - $form.setError(field) + form.setError(field) } } @@ -201,7 +198,7 @@ formEvents.forEach((e) => formElement?.removeEventListener(e, updateDirtyState)) } }) - const slotErrors = $derived($form.errors as Errors) + const slotErrors = $derived(form.errors as Errors)
{@render children?.({ errors: slotErrors, - hasErrors: $form.hasErrors, - processing: $form.processing, - progress: $form.progress, - wasSuccessful: $form.wasSuccessful, - recentlySuccessful: $form.recentlySuccessful, + hasErrors: form.hasErrors, + processing: form.processing, + progress: form.progress, + wasSuccessful: form.wasSuccessful, + recentlySuccessful: form.recentlySuccessful, isDirty, clearErrors, setError, reset, defaults, submit, - data: $form + data: form })}
diff --git a/packages/svelte5/src/index.ts b/packages/svelte5/src/index.ts index f1e062da1..1b2fff0d5 100644 --- a/packages/svelte5/src/index.ts +++ b/packages/svelte5/src/index.ts @@ -7,7 +7,7 @@ export { default as createInertiaApp } from './createInertiaApp' export { default as inertia } from './link' export { default as page } from './page' export { type ResolvedComponent } from './types' -export { default as useForm, type InertiaForm, type InertiaFormProps } from './useForm' +export { default as useForm, type InertiaFormRunes, type InertiaFormProps } from './useForm.svelte' export { default as usePoll } from './usePoll' export { default as usePrefetch } from './usePrefetch' export { default as useRemember } from './useRemember' diff --git a/packages/svelte5/src/useForm.svelte.ts b/packages/svelte5/src/useForm.svelte.ts new file mode 100644 index 000000000..2b1cc2375 --- /dev/null +++ b/packages/svelte5/src/useForm.svelte.ts @@ -0,0 +1,315 @@ +import type { + Errors, + ErrorValue, + FormDataErrors, + FormDataKeys, + FormDataType, + Method, + Progress, + VisitOptions, +} from '@inertiajs/core' +import { router } from '@inertiajs/core' +import { cloneDeep, get, has, isEqual, set } from 'lodash-es' + +type FormOptions = Omit + +export interface InertiaFormProps { + isDirty: boolean + errors: FormDataErrors + hasErrors: boolean + progress: Progress | null + wasSuccessful: boolean + recentlySuccessful: boolean + processing: boolean + data(): TForm + transform(callback: (data: TForm) => object): InertiaFormRunes + defaults(field?: FormDataKeys, value?: unknown): InertiaFormRunes + defaults(fields?: Partial): InertiaFormRunes + defaults(): InertiaFormRunes + reset(...fields: FormDataKeys[]): InertiaFormRunes + setError(field: FormDataKeys, value: ErrorValue): InertiaFormRunes + setError(errors: FormDataErrors): InertiaFormRunes + clearErrors(...fields: FormDataKeys[]): InertiaFormRunes + submit(method: Method, url: string, options?: FormOptions): void + get(url: string, options?: FormOptions): void + post(url: string, options?: FormOptions): void + put(url: string, options?: FormOptions): void + patch(url: string, options?: FormOptions): void + delete(url: string, options?: FormOptions): void + cancel(): void +} + +export type InertiaFormRunes = InertiaFormProps & TForm + +export default function useForm>( + data: TForm | (() => TForm) +): InertiaFormRunes +export default function useForm>( + rememberKey: string, + data: TForm | (() => TForm) +): InertiaFormRunes +export default function useForm>( + rememberKeyOrData: string | TForm | (() => TForm), + maybeData?: TForm | (() => TForm) +): InertiaFormRunes { + const rememberKey = typeof rememberKeyOrData === 'string' ? rememberKeyOrData : null + const inputData = (typeof rememberKeyOrData === 'string' ? maybeData : rememberKeyOrData) ?? {} + const initialData: TForm = typeof inputData === 'function' ? inputData() : (inputData as TForm) + + const restored = rememberKey + ? (router.restore(rememberKey) as { data: TForm; errors: Record, string> } | null) + : null + + let defaults = cloneDeep(initialData) + let cancelToken: { cancel: () => void } | null = null + let recentlySuccessfulTimeoutId: ReturnType | null = null + let transform = (data: TForm) => data as object + let defaultsCalledInOnSuccess = false + + // Create reactive state using $state runes + let formData = $state(restored ? restored.data : initialData) + let isDirty = $state(false) + let errors = $state>((restored ? restored.errors : {}) as FormDataErrors) + let hasErrors = $state(false) + let progress = $state(null) + let wasSuccessful = $state(false) + let recentlySuccessful = $state(false) + let processing = $state(false) + + // Derived state for hasErrors + $effect(() => { + hasErrors = Object.keys(errors).length > 0 + }) + + // Derived state for isDirty + $effect(() => { + isDirty = !isEqual(getData(), defaults) + }) + + function getData(): TForm { + return Object.keys(initialData).reduce((carry, key) => { + return set(carry, key, get(formData, key)) + }, {} as TForm) + } + + function setFormData(keyOrData: keyof TForm | TForm, maybeValue?: unknown) { + if (typeof keyOrData === 'string') { + set(formData, keyOrData, maybeValue) + } else { + Object.assign(formData, keyOrData) + } + } + + const form: InertiaFormRunes = { + ...formData, + get isDirty() { return isDirty }, + get errors() { return errors }, + get hasErrors() { return hasErrors }, + get progress() { return progress }, + get wasSuccessful() { return wasSuccessful }, + get recentlySuccessful() { return recentlySuccessful }, + get processing() { return processing }, + + data() { + return getData() + }, + + transform(callback) { + transform = callback + return form + }, + + defaults(fieldOrFields?: FormDataKeys | Partial, maybeValue?: unknown) { + defaultsCalledInOnSuccess = true + + if (typeof fieldOrFields === 'undefined') { + defaults = cloneDeep(getData()) + } else { + defaults = + typeof fieldOrFields === 'string' + ? set(cloneDeep(defaults), fieldOrFields, maybeValue) + : Object.assign(cloneDeep(defaults), fieldOrFields) + } + + return form + }, + + reset(...fields: FormDataKeys[]) { + const clonedData = cloneDeep(defaults) + if (fields.length === 0) { + setFormData(clonedData) + } else { + const resetData = fields + .filter((key) => has(clonedData, key)) + .reduce((carry, key) => { + return set(carry, key, get(clonedData, key)) + }, {} as Partial) + setFormData(resetData as TForm) + } + + return form + }, + + setError(fieldOrFields: FormDataKeys | FormDataErrors, maybeValue?: ErrorValue) { + errors = { + ...errors, + ...((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as FormDataErrors), + } + + return form + }, + + clearErrors(...fields: FormDataKeys[]) { + errors = Object.keys(errors).reduce( + (carry, field) => ({ + ...carry, + ...(fields.length > 0 && !fields.includes(field as FormDataKeys) ? { [field]: errors[field as keyof FormDataErrors] } : {}), + }), + {} as FormDataErrors + ) + + return form + }, + + submit(method: Method, url: string, options: FormOptions = {}) { + const data = transform(getData()) + const _options = { + ...options, + onCancelToken: (token: { cancel: () => void }) => { + cancelToken = token + + if (options.onCancelToken) { + return options.onCancelToken(token) + } + }, + onBefore: (visit) => { + wasSuccessful = false + recentlySuccessful = false + defaultsCalledInOnSuccess = false + + if (recentlySuccessfulTimeoutId) { + clearTimeout(recentlySuccessfulTimeoutId) + } + + if (options.onBefore) { + return options.onBefore(visit) + } + }, + onStart: (visit) => { + processing = true + + if (options.onStart) { + return options.onStart(visit) + } + }, + onProgress: (event) => { + progress = event + + if (options.onProgress) { + return options.onProgress(event) + } + }, + onSuccess: async (page) => { + processing = false + progress = null + errors = {} as FormDataErrors + wasSuccessful = true + recentlySuccessful = true + + recentlySuccessfulTimeoutId = setTimeout(() => { + recentlySuccessful = false + }, 2000) + + const result = options.onSuccess ? await options.onSuccess(page) : null + + if (!defaultsCalledInOnSuccess) { + defaults = cloneDeep(getData()) + } + + return result + }, + onError: async (errors) => { + processing = false + progress = null + form.errors = errors as FormDataErrors + + if (options.onError) { + return await options.onError(errors) + } + }, + onCancel: () => { + processing = false + progress = null + + if (options.onCancel) { + return options.onCancel() + } + }, + onFinish: (visit) => { + processing = false + progress = null + cancelToken = null + + if (options.onFinish) { + return options.onFinish(visit) + } + }, + } + + if (method === 'delete') { + router.delete(url, { ..._options, data }) + } else { + router[method](url, data, _options) + } + }, + + get(url: string, options: FormOptions = {}) { + form.submit('get', url, options) + }, + + post(url: string, options: FormOptions = {}) { + form.submit('post', url, options) + }, + + put(url: string, options: FormOptions = {}) { + form.submit('put', url, options) + }, + + patch(url: string, options: FormOptions = {}) { + form.submit('patch', url, options) + }, + + delete(url: string, options: FormOptions = {}) { + form.submit('delete', url, options) + }, + + cancel() { + cancelToken?.cancel() + }, + } as InertiaFormRunes + + // Set up reactive updates for form data properties + $effect(() => { + Object.keys(initialData).forEach(key => { + Object.defineProperty(form, key, { + get() { + return get(formData, key) + }, + set(value) { + set(formData, key, value) + }, + enumerable: true, + configurable: true + }) + }) + }) + + // Set up remember functionality + $effect(() => { + if (rememberKey) { + router.remember({ data: getData(), errors }, rememberKey) + } + }) + + return form +} diff --git a/packages/svelte5/src/useForm.ts b/packages/svelte5/src/useForm.ts deleted file mode 100644 index 2d034e3ce..000000000 --- a/packages/svelte5/src/useForm.ts +++ /dev/null @@ -1,290 +0,0 @@ -import type { - ActiveVisit, - Errors, - ErrorValue, - FormDataErrors, - FormDataKeys, - FormDataType, - FormDataValues, - Method, - Page, - PendingVisit, - Progress, - RequestPayload, - UrlMethodPair, - VisitOptions, -} from '@inertiajs/core' -import { router } from '@inertiajs/core' -import type { AxiosProgressEvent } from 'axios' -import { cloneDeep, get, has, isEqual, set } from 'lodash-es' -import { writable, type Writable } from 'svelte/store' - -type InertiaFormStore = Writable> & InertiaForm - -type FormOptions = Omit - -export interface InertiaFormProps { - isDirty: boolean - errors: FormDataErrors - hasErrors: boolean - progress: Progress | null - wasSuccessful: boolean - recentlySuccessful: boolean - processing: boolean - setStore(data: TForm): void - setStore>(key: T, value: FormDataValues): void - data(): TForm - transform(callback: (data: TForm) => object): this - defaults(): this - defaults(fields: Partial): this - defaults>(field: T, value: FormDataValues): this - reset>(...fields: K[]): this - clearErrors>(...fields: K[]): this - resetAndClearErrors>(...fields: K[]): this - setError>(field: K, value: ErrorValue): this - setError(errors: FormDataErrors): this - submit: (...args: [Method, string, FormOptions?] | [UrlMethodPair, FormOptions?]) => void - get(url: string, options?: FormOptions): void - post(url: string, options?: FormOptions): void - put(url: string, options?: FormOptions): void - patch(url: string, options?: FormOptions): void - delete(url: string, options?: FormOptions): void - cancel(): void -} - -export type InertiaForm = InertiaFormProps & TForm - -export default function useForm>(data: TForm | (() => TForm)): InertiaFormStore -export default function useForm>( - rememberKey: string, - data: TForm | (() => TForm), -): InertiaFormStore -export default function useForm>( - rememberKeyOrData: string | TForm | (() => TForm), - maybeData?: TForm | (() => TForm), -): InertiaFormStore { - const rememberKey = typeof rememberKeyOrData === 'string' ? rememberKeyOrData : null - const inputData = (typeof rememberKeyOrData === 'string' ? maybeData : rememberKeyOrData) ?? {} - const data: TForm = typeof inputData === 'function' ? inputData() : (inputData as TForm) - const restored = rememberKey - ? (router.restore(rememberKey) as { data: TForm; errors: Record, string> } | null) - : null - let defaults = cloneDeep(data) - let cancelToken: { cancel: () => void } | null = null - let recentlySuccessfulTimeoutId: ReturnType | null = null - let transform = (data: TForm) => data as object - // Track if defaults was called manually during onSuccess to avoid - // overriding user's custom defaults with automatic behavior. - let defaultsCalledInOnSuccess = false - - const store = writable>({ - ...(restored ? restored.data : data), - isDirty: false, - errors: (restored ? restored.errors : {}) as FormDataErrors, - hasErrors: false, - progress: null, - wasSuccessful: false, - recentlySuccessful: false, - processing: false, - setStore(keyOrData: keyof InertiaFormProps | FormDataKeys | TForm, maybeValue = undefined) { - store.update((store) => { - return typeof keyOrData === 'string' ? set(store, keyOrData, maybeValue) : Object.assign(store, keyOrData) - }) - }, - data() { - return Object.keys(data).reduce((carry, key) => { - return set(carry, key, get(this, key)) - }, {} as TForm) - }, - transform(callback) { - transform = callback - return this - }, - defaults(fieldOrFields?: FormDataKeys | Partial, maybeValue?: unknown) { - defaultsCalledInOnSuccess = true - - if (typeof fieldOrFields === 'undefined') { - defaults = cloneDeep(this.data()) - } else { - defaults = - typeof fieldOrFields === 'string' - ? set(cloneDeep(defaults), fieldOrFields, maybeValue) - : Object.assign(cloneDeep(defaults), fieldOrFields) - } - - return this - }, - reset(...fields) { - const clonedData = cloneDeep(defaults) - if (fields.length === 0) { - this.setStore(clonedData) - } else { - this.setStore( - fields - .filter((key) => has(clonedData, key)) - .reduce((carry, key) => { - return set(carry, key, get(clonedData, key)) - }, {} as TForm), - ) - } - - return this - }, - setError(fieldOrFields: FormDataKeys | FormDataErrors, maybeValue?: ErrorValue) { - this.setStore('errors', { - ...this.errors, - ...((typeof fieldOrFields === 'string' ? { [fieldOrFields]: maybeValue } : fieldOrFields) as Errors), - }) - - return this - }, - clearErrors(...fields) { - this.setStore( - 'errors', - Object.keys(this.errors).reduce( - (carry, field) => ({ - ...carry, - ...(fields.length > 0 && !fields.includes(field) ? { [field]: this.errors[field] } : {}), - }), - {}, - ) as Errors, - ) - return this - }, - resetAndClearErrors(...fields) { - this.reset(...fields) - this.clearErrors(...fields) - return this - }, - submit(...args) { - const objectPassed = args[0] !== null && typeof args[0] === 'object' - - const method = objectPassed ? args[0].method : args[0] - const url = objectPassed ? args[0].url : args[1] - const options = (objectPassed ? args[1] : args[2]) ?? {} - - defaultsCalledInOnSuccess = false - - const data = transform(this.data()) as RequestPayload - - const _options: Omit = { - ...options, - onCancelToken: (token: { cancel: () => void }) => { - cancelToken = token - - if (options.onCancelToken) { - return options.onCancelToken(token) - } - }, - onBefore: (visit: PendingVisit) => { - this.setStore('wasSuccessful', false) - this.setStore('recentlySuccessful', false) - if (recentlySuccessfulTimeoutId) { - clearTimeout(recentlySuccessfulTimeoutId) - } - - if (options.onBefore) { - return options.onBefore(visit) - } - }, - onStart: (visit: PendingVisit) => { - this.setStore('processing', true) - - if (options.onStart) { - return options.onStart(visit) - } - }, - onProgress: (event?: AxiosProgressEvent) => { - this.setStore('progress', event as any) - - if (options.onProgress) { - return options.onProgress(event) - } - }, - onSuccess: async (page: Page) => { - this.setStore('processing', false) - this.setStore('progress', null) - this.clearErrors() - this.setStore('wasSuccessful', true) - this.setStore('recentlySuccessful', true) - recentlySuccessfulTimeoutId = setTimeout(() => this.setStore('recentlySuccessful', false), 2000) - - const onSuccess = options.onSuccess ? await options.onSuccess(page) : null - - if (!defaultsCalledInOnSuccess) { - this.defaults(cloneDeep(this.data())) - } - - return onSuccess - }, - onError: (errors: Errors) => { - this.setStore('processing', false) - this.setStore('progress', null) - this.clearErrors().setError(errors) - - if (options.onError) { - return options.onError(errors) - } - }, - onCancel: () => { - this.setStore('processing', false) - this.setStore('progress', null) - - if (options.onCancel) { - return options.onCancel() - } - }, - onFinish: (visit: ActiveVisit) => { - this.setStore('processing', false) - this.setStore('progress', null) - cancelToken = null - - if (options.onFinish) { - return options.onFinish(visit) - } - }, - } - - if (method === 'delete') { - router.delete(url, { ..._options, data }) - } else { - router[method](url, data, _options) - } - }, - get(url, options) { - this.submit('get', url, options) - }, - post(url, options) { - this.submit('post', url, options) - }, - put(url, options) { - this.submit('put', url, options) - }, - patch(url, options) { - this.submit('patch', url, options) - }, - delete(url, options) { - this.submit('delete', url, options) - }, - cancel() { - cancelToken?.cancel() - }, - } as InertiaForm) - - store.subscribe((form) => { - if (form.isDirty === isEqual(form.data(), defaults)) { - form.setStore('isDirty', !form.isDirty) - } - - const hasErrors = Object.keys(form.errors).length > 0 - if (form.hasErrors !== hasErrors) { - form.setStore('hasErrors', !form.hasErrors) - } - - if (rememberKey) { - router.remember({ data: form.data(), errors: form.errors }, rememberKey) - } - }) - - return store -} diff --git a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte index e2ce52797..ff7253ec0 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte @@ -7,7 +7,7 @@

Form Elements

- Form is {isDirty ? 'dirty' : 'clean'} + {#if isDirty}Form is dirty{:else}Form is clean{/if}
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Data.svelte b/packages/svelte5/test-app/Pages/FormHelper/Data.svelte index 5a119b124..0ef942155 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Data.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Data.svelte @@ -8,7 +8,7 @@ }) const submit = () => { - form.post(page.url) + form.post($page.url) } const submitAndReset = () => { From 990698285f3b0777ff6b75b8616c5ad368788db5 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:27:44 +1000 Subject: [PATCH 022/112] refactor(FormHelper): remove $ prefix from form usage Update Errors.svelte, Methods.svelte, and Transform.svelte to use the direct form variable instead of the $form store syntax. This aligns with the updated FormHelper API and improves code clarity. --- .../test-app/Pages/FormHelper/Errors.svelte | 36 ++++++++++--------- .../test-app/Pages/FormHelper/Methods.svelte | 19 +++++----- .../Pages/FormHelper/Transform.svelte | 12 +++---- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte b/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte index e88a89a6f..75f363527 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte @@ -8,58 +8,60 @@ }) const submit = () => { - $form.post('/form-helper/errors') + form.post('/form-helper/errors') } const clearErrors = () => { - $form.clearErrors() + form.clearErrors() } const clearError = () => { - $form.clearErrors('handle') + form.clearErrors('handle') } const setErrors = () => { - $form.setError({ + form.setError({ name: 'Manually set Name error', handle: 'Manually set Handle error', }) } const setError = () => { - $form.setError('handle', 'Manually set Handle error') + form.setError('handle', 'Manually set Handle error') } const resetAndClearErrors = () => { - $form.resetAndClearErrors() + form.reset() + form.clearErrors() } const resetHandle = () => { - $form.resetAndClearErrors('handle') + form.reset('handle') + form.clearErrors('handle') }
- {#if $form.errors.name} - {$form.errors.name} + {#if form.errors.name} + {form.errors.name} {/if} - {#if $form.errors.handle} - {$form.errors.handle} + {#if form.errors.handle} + {form.errors.handle} {/if} - {#if $form.errors.remember} - {$form.errors.remember} + {#if form.errors.remember} + {form.errors.remember} {/if} @@ -71,5 +73,5 @@ - Form has {$form.hasErrors ? '' : 'no '}errors + Form has {form.hasErrors ? '' : 'no '}errors
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte b/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte index c03d19160..527b36471 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte @@ -7,41 +7,38 @@ }) const postForm = () => { - $form.post('/dump/post') + form.post('/dump/post') } const putForm = () => { - $form.put('/dump/put') + form.put('/dump/put') } const patchForm = () => { - $form.patch('/dump/patch') + form.patch('/dump/patch') } const deleteForm = () => { - $form.delete('/dump/delete') + form.delete('/dump/delete') } const submitForm = () => { - $form.submit('post', '/dump/post') + form.submit('post', '/dump/post') } const submitFormObject = () => { - $form.submit({ - method: 'post', - url: '/dump/post', - }) + form.submit('post', '/dump/post') }
diff --git a/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte b/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte index 12ceabd45..b0962b486 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Transform.svelte @@ -7,7 +7,7 @@ }) const postForm = () => { - $form + form .transform((data) => ({ ...data, name: 'bar', @@ -16,7 +16,7 @@ } const putForm = () => { - $form + form .transform((data) => ({ ...data, name: 'baz', @@ -25,7 +25,7 @@ } const patchForm = () => { - $form + form .transform((data) => ({ ...data, name: 'foo', @@ -34,7 +34,7 @@ } const deleteForm = () => { - $form + form .transform((data) => ({ ...data, name: 'bar', @@ -46,11 +46,11 @@
From 461cffc1d67f6c7a5d4845d6df90028329c33e6d Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:31:54 +1000 Subject: [PATCH 023/112] refactor(FormHelper): remove $ prefix from form usage Update all references from $form to form in Dirty.svelte to align with Svelte's store usage best practices. This change improves code clarity and consistency. --- .../test-app/Pages/FormHelper/Dirty.svelte | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte b/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte index 4ac4b24df..824747fb3 100644 --- a/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte +++ b/packages/svelte5/test-app/Pages/FormHelper/Dirty.svelte @@ -7,15 +7,15 @@ }) const submit = () => { - $form.post('') + form.post('') } const defaults = () => { - $form.defaults() + form.defaults() } const pushValue = () => { - $form.foo.push('bar') + form.foo.push('bar') } const dataAndDefaults = () => { @@ -24,25 +24,25 @@ } const submitAndSetDefaults = () => { - $form.post('/form-helper/dirty/redirect-back', { - onSuccess: () => $form.defaults(), + form.post('/form-helper/dirty/redirect-back', { + onSuccess: () => form.defaults(), }) } const submitAndSetCustomDefaults = () => { - $form.post('/form-helper/dirty/redirect-back', { - onSuccess: () => $form.defaults({ name: 'Custom Default', foo: [] }), + form.post('/form-helper/dirty/redirect-back', { + onSuccess: () => form.defaults({ name: 'Custom Default', foo: [] }), }) }
- Form is {#if $form.isDirty}dirty{:else}clean{/if} + Form is {#if form.isDirty}dirty{:else}clean{/if}
From e1bf42a3e2ca5fbcc9a181b16e226e69149f352a Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:33:44 +1000 Subject: [PATCH 024/112] refactor(FormComponent): update Reset.svelte children Refactor Reset.svelte to use the snippet block for children and remove the let:errors prop from the Form component. This improves code clarity and aligns with updated Svelte syntax. --- .../test-app/Pages/FormComponent/SubmitComplete/Reset.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte index 5103f0d0b..4e19398b1 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte @@ -5,7 +5,8 @@

OnSubmitComplete Reset Test

-
props.reset('name')}> + props.reset('name')}> + {#snippet children({ errors })}
{#if errors.name} @@ -23,5 +24,6 @@
+ {/snippet}
From adb6a9b9e3c0f4ea3980a92a9e7f0f59cc08beb0 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:33:51 +1000 Subject: [PATCH 025/112] refactor(FormComponent): use snippet for form children Refactor Defaults.svelte to wrap form fields in a snippet block, passing errors and isDirty to children. This improves code clarity and aligns with updated component patterns. --- .../SubmitComplete/Defaults.svelte | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte index 25ca9bbd2..8acbd6a03 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte @@ -5,27 +5,29 @@

OnSubmitComplete Defaults Test

-
props.defaults()}> -
-

{isDirty ? 'Form is dirty' : 'Form is clean'}

-
+ props.defaults()}> + {#snippet children({ errors, isDirty })} +
+

{isDirty ? 'Form is dirty' : 'Form is clean'}

+
-
- - {#if errors.name} -

{errors.name}

- {/if} -
+
+ + {#if errors.name} +

{errors.name}

+ {/if} +
-
- - {#if errors.email} -

{errors.email}

- {/if} -
+
+ + {#if errors.email} +

{errors.email}

+ {/if} +
-
- -
+
+ +
+ {/snippet}
From 0d719a1865c4194a2f62f944db10a35a15e6f813 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:36:30 +1000 Subject: [PATCH 026/112] refactor(form): use snippet for form children Refactor Form usage to wrap children in a snippet block, enabling access to isDirty, errors, and hasErrors via the snippet context instead of let directives. This aligns with updated Svelte syntax and improves code clarity. --- .../test-app/Pages/FormComponent/Ref.svelte | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte b/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte index 9c0b20d39..20cd76adf 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte @@ -33,27 +33,29 @@

Form Ref Test

-
- -
Form is {isDirty ? 'dirty' : 'clean'}
- {#if hasErrors} -
Form has errors
- {/if} - {#if errors.name} -
{errors.name}
- {/if} + + {#snippet children({ isDirty, errors, hasErrors })} + +
Form is {isDirty ? 'dirty' : 'clean'}
+ {#if hasErrors} +
Form has errors
+ {/if} + {#if errors.name} +
{errors.name}
+ {/if} -
- -
+
+ +
-
- -
+
+ +
-
- -
+
+ +
+ {/snippet}
From fef47836443becf7e38e61b5445d38aab7c7b0c1 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:43:17 +1000 Subject: [PATCH 027/112] fix(useForm): correct error handling in onError callback Update the onError callback to assign errors to the local variable instead of form.errors and ensure the correct parameter is passed to user-defined onError handlers. Also, call form.defaults() after successful submission if defaults were not set in onSuccess. --- packages/svelte5/src/useForm.svelte.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/svelte5/src/useForm.svelte.ts b/packages/svelte5/src/useForm.svelte.ts index 2b1cc2375..4a327ea48 100644 --- a/packages/svelte5/src/useForm.svelte.ts +++ b/packages/svelte5/src/useForm.svelte.ts @@ -223,18 +223,18 @@ export default function useForm>( const result = options.onSuccess ? await options.onSuccess(page) : null if (!defaultsCalledInOnSuccess) { - defaults = cloneDeep(getData()) + form.defaults() } return result }, - onError: async (errors) => { + onError: async (errorResponse) => { processing = false progress = null - form.errors = errors as FormDataErrors + errors = errorResponse as FormDataErrors if (options.onError) { - return await options.onError(errors) + return await options.onError(errorResponse) } }, onCancel: () => { From fea83cfdd43572aa223dfa5c50eb244f695bb6f7 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:28:59 +1000 Subject: [PATCH 028/112] fix(useForm): improve reactivity and reset logic Wrap defaults in $state for reactivity and update setFormData to trigger updates for each property. Refactor reset to handle specific fields more reliably and ensure correct default values are restored. --- packages/svelte5/src/useForm.svelte.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/svelte5/src/useForm.svelte.ts b/packages/svelte5/src/useForm.svelte.ts index 4a327ea48..131a35314 100644 --- a/packages/svelte5/src/useForm.svelte.ts +++ b/packages/svelte5/src/useForm.svelte.ts @@ -60,7 +60,7 @@ export default function useForm>( ? (router.restore(rememberKey) as { data: TForm; errors: Record, string> } | null) : null - let defaults = cloneDeep(initialData) + let defaults = $state(cloneDeep(initialData)) let cancelToken: { cancel: () => void } | null = null let recentlySuccessfulTimeoutId: ReturnType | null = null let transform = (data: TForm) => data as object @@ -96,7 +96,10 @@ export default function useForm>( if (typeof keyOrData === 'string') { set(formData, keyOrData, maybeValue) } else { - Object.assign(formData, keyOrData) + // For runes, we need to update each property individually to trigger reactivity + Object.keys(keyOrData).forEach(key => { + set(formData, key, get(keyOrData, key)) + }) } } @@ -135,16 +138,18 @@ export default function useForm>( }, reset(...fields: FormDataKeys[]) { - const clonedData = cloneDeep(defaults) if (fields.length === 0) { + // Reset all fields + const clonedData = cloneDeep(defaults) setFormData(clonedData) } else { - const resetData = fields - .filter((key) => has(clonedData, key)) - .reduce((carry, key) => { - return set(carry, key, get(clonedData, key)) - }, {} as Partial) - setFormData(resetData as TForm) + // Reset specific fields + fields.forEach(field => { + if (has(defaults, field)) { + const defaultValue = get(defaults, field) + setFormData(field as keyof TForm, defaultValue) + } + }) } return form From 2901ea62e3ce3cb5f3af25a78b5abbfe4cff0e19 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:41:01 +1000 Subject: [PATCH 029/112] fix(form): add id to error message div Assign id 'error_name' to the name error message div for improved testability and accessibility. --- .../svelte5/test-app/Pages/FormComponent/EmptyAction.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte index ba4758f24..e72083d4c 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte @@ -10,7 +10,7 @@
{#if errors.name} -
{errors.name}
+
{errors.name}
{/if}
From f39a609d86f6ad3d27996b87336cce49d20b45e7 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:43:47 +1000 Subject: [PATCH 030/112] refactor(useForm): improve defaults update logic Refactor the logic for updating form defaults to handle single and multiple field updates more clearly. This change improves code readability and ensures that defaults are always cloned before modification. --- packages/svelte5/src/useForm.svelte.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/svelte5/src/useForm.svelte.ts b/packages/svelte5/src/useForm.svelte.ts index 131a35314..5c4cb928d 100644 --- a/packages/svelte5/src/useForm.svelte.ts +++ b/packages/svelte5/src/useForm.svelte.ts @@ -127,11 +127,16 @@ export default function useForm>( if (typeof fieldOrFields === 'undefined') { defaults = cloneDeep(getData()) + } else if (typeof fieldOrFields === 'string') { + // Update single field + const newDefaults = cloneDeep(defaults) + set(newDefaults, fieldOrFields, maybeValue) + defaults = newDefaults } else { - defaults = - typeof fieldOrFields === 'string' - ? set(cloneDeep(defaults), fieldOrFields, maybeValue) - : Object.assign(cloneDeep(defaults), fieldOrFields) + // Update multiple fields + const newDefaults = cloneDeep(defaults) + Object.assign(newDefaults, fieldOrFields) + defaults = newDefaults } return form From bf61286cf88ab35c813dda6de11769811adea705 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:01:07 +1000 Subject: [PATCH 031/112] refactor(test-app): make window props reactive to page Update Svelte test app components to assign window properties reactively when $page.props changes, ensuring global props stay in sync with page state. This replaces static assignments with $effect blocks for better reactivity and correctness. --- .../svelte5/test-app/Layouts/NestedLayout.svelte | 8 +++++++- .../svelte5/test-app/Layouts/SiteLayout.svelte | 8 +++++++- packages/svelte5/test-app/Pages/Home.svelte | 8 +++++++- .../Shorthand/Nested/PageA.svelte | 7 ++++++- .../Shorthand/Nested/PageB.svelte | 7 ++++++- .../Shorthand/Simple/PageA.svelte | 7 ++++++- .../Shorthand/Simple/PageB.svelte | 7 ++++++- .../test-app/Pages/Visits/PartialReloads.svelte | 14 +++++++++----- 8 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/svelte5/test-app/Layouts/NestedLayout.svelte b/packages/svelte5/test-app/Layouts/NestedLayout.svelte index aa99a6cbc..911639692 100644 --- a/packages/svelte5/test-app/Layouts/NestedLayout.svelte +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -6,9 +6,15 @@ onMount(() => { window._inertia_nested_layout_id = crypto.randomUUID() - window._inertia_nested_layout_props = page.props createdAt = Date.now() }) + + // Update props reactively when page changes + $effect(() => { + if (typeof window !== 'undefined') { + window._inertia_nested_layout_props = $page.props + } + })
diff --git a/packages/svelte5/test-app/Layouts/SiteLayout.svelte b/packages/svelte5/test-app/Layouts/SiteLayout.svelte index 46dca6873..23f8daabb 100644 --- a/packages/svelte5/test-app/Layouts/SiteLayout.svelte +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -6,9 +6,15 @@ onMount(() => { window._inertia_layout_id = crypto.randomUUID() - window._inertia_site_layout_props = page.props createdAt = Date.now() }) + + // Update props reactively when page changes + $effect(() => { + if (typeof window !== 'undefined') { + window._inertia_site_layout_props = $page.props + } + })
diff --git a/packages/svelte5/test-app/Pages/Home.svelte b/packages/svelte5/test-app/Pages/Home.svelte index 1b3943dbf..3ce38061a 100644 --- a/packages/svelte5/test-app/Pages/Home.svelte +++ b/packages/svelte5/test-app/Pages/Home.svelte @@ -20,9 +20,15 @@ onMount(() => { window._inertia_page_key = crypto.randomUUID() - window._inertia_props = $page.props window._plugin_global_props = {} }) + + // Update props reactively when page changes + $effect(() => { + if (typeof window !== 'undefined') { + window._inertia_props = $page.props + } + })
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte index 0cc356bfb..2e1084e49 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte @@ -8,7 +8,12 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte index f4fc7f822..28776c5cf 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte @@ -8,7 +8,12 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte index a45ab415c..d536b337f 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte @@ -7,7 +7,12 @@
diff --git a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte index 9d2e99813..e4b6e5d3b 100644 --- a/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte @@ -7,7 +7,12 @@
diff --git a/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte index 1ee8a0ec5..e66626766 100644 --- a/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte +++ b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte @@ -2,13 +2,17 @@ import { page, router } from '@inertiajs/svelte5' import { onMount } from 'svelte' - export let foo - export let bar - export let baz - export let headers + const { foo, bar, baz, headers } = $props() onMount(() => { - window._inertia_props = page.props + // Other initialization if needed + }) + + // Update props reactively when page changes + $effect(() => { + if (typeof window !== 'undefined') { + window._inertia_props = $page.props + } }) const partialReloadVisit = () => { From 874815a39c4a013781afbf9d8c8cc23043ba7daa Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:09:43 +1000 Subject: [PATCH 032/112] refactor(test-app): use $props in Svelte pages Refactor Svelte test app pages to use $props() for prop extraction instead of export let syntax. This improves consistency and leverages Svelte 5 conventions for props handling. --- .../svelte5/test-app/Pages/ClientSideVisit/Page1.svelte | 9 ++++----- .../Pages/FormComponent/DisableWhileProcessing.svelte | 2 +- packages/svelte5/test-app/Pages/History/Page.svelte | 3 +-- .../svelte5/test-app/Pages/Links/PartialReloads.svelte | 5 +---- .../svelte5/test-app/Pages/Visits/PreserveState.svelte | 2 +- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte b/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte index 0d5525980..6b2ce6e57 100644 --- a/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte +++ b/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte @@ -7,12 +7,11 @@ bar: string } - export let foo: string - export let bar: string + const { foo, bar }: { foo: string; bar: string } = $props() - let errors = 0 - let finished = 0 - let success = 0 + let errors = $state(0) + let finished = $state(0) + let success = $state(0) const bagErrors = () => { router.replace({ diff --git a/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte index 4e447d0e2..f7a9eacb8 100644 --- a/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte +++ b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte @@ -1,6 +1,6 @@ diff --git a/packages/svelte5/test-app/Pages/History/Page.svelte b/packages/svelte5/test-app/Pages/History/Page.svelte index 175120d91..98b1ccca3 100644 --- a/packages/svelte5/test-app/Pages/History/Page.svelte +++ b/packages/svelte5/test-app/Pages/History/Page.svelte @@ -1,8 +1,7 @@ Page 1 diff --git a/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte index f657f464a..eaaecf153 100644 --- a/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte +++ b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte @@ -1,10 +1,7 @@
diff --git a/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte b/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte index d12d6b40c..1275a4fc8 100644 --- a/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte +++ b/packages/svelte5/test-app/Pages/Visits/PreserveState.svelte @@ -2,7 +2,7 @@ import { router } from '@inertiajs/svelte5' import { onMount } from 'svelte' - export let foo = 'default' + const { foo = 'default' } = $props() onMount(() => { window._inertia_page_key = crypto.randomUUID() From 664c03826b2593e8e009046e01fde26ac79be1d4 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:20:55 +1000 Subject: [PATCH 033/112] refactor(test-app): use $props in Svelte5 components Refactor all test-app Svelte components to use the $props() helper for prop access instead of Svelte's export let syntax. This aligns with the new recommended pattern for prop handling in Svelte5 and improves consistency across the codebase. Also updates some state and effect usage to match Svelte5 idioms. --- .../test-app/Layouts/NestedLayout.svelte | 5 +++-- .../svelte5/test-app/Layouts/SiteLayout.svelte | 5 +++-- packages/svelte5/test-app/Pages/Article.svelte | 3 ++- .../test-app/Pages/DeferredProps/Page1.svelte | 3 +-- packages/svelte5/test-app/Pages/Dump.svelte | 18 ++++++++++-------- .../test-app/Pages/Links/AsWarning.svelte | 2 +- .../test-app/Pages/Links/AsWarningFalse.svelte | 2 +- .../Pages/Links/CancelSyncRequest.svelte | 2 +- .../test-app/Pages/Links/PreserveScroll.svelte | 2 +- .../Pages/Links/PreserveScrollFalse.svelte | 2 +- .../test-app/Pages/Links/PreserveState.svelte | 2 +- .../svelte5/test-app/Pages/MergeProps.svelte | 3 +-- .../test-app/Pages/Prefetch/Page.svelte | 3 +-- .../svelte5/test-app/Pages/Prefetch/SWR.svelte | 3 +-- .../test-app/Pages/Prefetch/Tags.svelte | 8 +++----- .../Pages/Svelte/PropsAndPageStore.svelte | 16 +++++++++------- .../Pages/Visits/PreserveScroll.svelte | 2 +- .../Pages/Visits/PreserveScrollFalse.svelte | 2 +- .../test-app/Pages/Visits/ReloadOnMount.svelte | 2 +- .../svelte5/test-app/Pages/WhenVisible.svelte | 3 ++- 20 files changed, 45 insertions(+), 43 deletions(-) diff --git a/packages/svelte5/test-app/Layouts/NestedLayout.svelte b/packages/svelte5/test-app/Layouts/NestedLayout.svelte index 911639692..45a78479a 100644 --- a/packages/svelte5/test-app/Layouts/NestedLayout.svelte +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -2,7 +2,8 @@ import { onMount } from 'svelte' import { page } from '@inertiajs/svelte5' - let createdAt: number | null = null + const { children } = $props() + let createdAt = $state(null) onMount(() => { window._inertia_nested_layout_id = crypto.randomUUID() @@ -21,6 +22,6 @@ Nested Layout {createdAt}
- + {@render children?.()}
diff --git a/packages/svelte5/test-app/Layouts/SiteLayout.svelte b/packages/svelte5/test-app/Layouts/SiteLayout.svelte index 23f8daabb..3113a1d0d 100644 --- a/packages/svelte5/test-app/Layouts/SiteLayout.svelte +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -2,7 +2,8 @@ import { onMount } from 'svelte' import { page } from '@inertiajs/svelte5' - let createdAt: number | null = null + const { children } = $props() + let createdAt = $state(null) onMount(() => { window._inertia_layout_id = crypto.randomUUID() @@ -21,6 +22,6 @@ Site Layout {createdAt}
- + {@render children?.()}
diff --git a/packages/svelte5/test-app/Pages/Article.svelte b/packages/svelte5/test-app/Pages/Article.svelte index 4b8fcd77c..2af8e1b5d 100644 --- a/packages/svelte5/test-app/Pages/Article.svelte +++ b/packages/svelte5/test-app/Pages/Article.svelte @@ -6,7 +6,8 @@ document.documentElement.style.scrollBehavior = 'smooth' } - export let scrollLog: number[] = [] + let { scrollLog = [] }: { scrollLog?: number[] } = $props() + let scrollLogState = $state(scrollLog) const handleScrollEvent = () => { scrollLog = [...scrollLog, document.documentElement.scrollTop] diff --git a/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte index a159ffa1c..94e844449 100644 --- a/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte @@ -1,8 +1,7 @@ diff --git a/packages/svelte5/test-app/Pages/Dump.svelte b/packages/svelte5/test-app/Pages/Dump.svelte index feb9071e1..76106c855 100644 --- a/packages/svelte5/test-app/Pages/Dump.svelte +++ b/packages/svelte5/test-app/Pages/Dump.svelte @@ -1,15 +1,16 @@ diff --git a/packages/svelte5/test-app/Pages/Links/AsWarning.svelte b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte index 19a44aefd..47eb071cc 100644 --- a/packages/svelte5/test-app/Pages/Links/AsWarning.svelte +++ b/packages/svelte5/test-app/Pages/Links/AsWarning.svelte @@ -1,7 +1,7 @@
diff --git a/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte index b89391cfc..7da654f03 100644 --- a/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte +++ b/packages/svelte5/test-app/Pages/Links/AsWarningFalse.svelte @@ -1,7 +1,7 @@
diff --git a/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte index 002bbc9d7..e57e136d7 100644 --- a/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte +++ b/packages/svelte5/test-app/Pages/Links/CancelSyncRequest.svelte @@ -1,7 +1,7 @@

diff --git a/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte index 672db774e..ff2a48a78 100644 --- a/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte +++ b/packages/svelte5/test-app/Pages/Links/PreserveScroll.svelte @@ -6,7 +6,7 @@ import { inertia } from '@inertiajs/svelte5' import type { Page } from '@inertiajs/core' - export let foo: string = 'default' + const { foo = 'default' }: { foo?: string } = $props() const preserveCallback = (page: Page) => { console.log(JSON.stringify(page)) diff --git a/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte b/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte index f3586fe40..2cce1a032 100644 --- a/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte +++ b/packages/svelte5/test-app/Pages/Links/PreserveScrollFalse.svelte @@ -6,7 +6,7 @@ import { inertia } from '@inertiajs/svelte5' import type { Page } from '@inertiajs/core' - export let foo: string = 'default' + const { foo = 'default' }: { foo?: string } = $props() const preserveCallback = (page: Page) => { console.log(JSON.stringify(page)) diff --git a/packages/svelte5/test-app/Pages/Links/PreserveState.svelte b/packages/svelte5/test-app/Pages/Links/PreserveState.svelte index 8efaf4199..3a37cf4e5 100644 --- a/packages/svelte5/test-app/Pages/Links/PreserveState.svelte +++ b/packages/svelte5/test-app/Pages/Links/PreserveState.svelte @@ -7,7 +7,7 @@ import { inertia } from '@inertiajs/svelte5' import type { Page } from '@inertiajs/core' - export let foo: string = 'default' + const { foo = 'default' }: { foo?: string } = $props() const preserveCallback = (page: Page) => { alert(page) diff --git a/packages/svelte5/test-app/Pages/MergeProps.svelte b/packages/svelte5/test-app/Pages/MergeProps.svelte index 3f8ea951c..eb1cfd72d 100644 --- a/packages/svelte5/test-app/Pages/MergeProps.svelte +++ b/packages/svelte5/test-app/Pages/MergeProps.svelte @@ -1,8 +1,7 @@
This is page {pageNumber}
diff --git a/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte b/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte index 0f42a6d2e..3c82677a3 100644 --- a/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte +++ b/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte @@ -3,8 +3,7 @@
This is page {pageNumber}
diff --git a/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte b/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte index 006ee5da3..8547a57c2 100644 --- a/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte +++ b/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte @@ -1,8 +1,6 @@

foo prop is {foo}

-

page.props.foo is {page.props.foo}

+

page.props.foo is {$page.props.foo}

pageProps.foo is {pageProps.foo}

Bar diff --git a/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte b/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte index b04fa80eb..2a28500a6 100644 --- a/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte +++ b/packages/svelte5/test-app/Pages/Visits/PreserveScroll.svelte @@ -5,7 +5,7 @@
From e5ed818481ad41061eebfa9034cc741795734f13 Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:21:02 +1000 Subject: [PATCH 034/112] feat(useForm): add reactive getters for form data Introduce reactive getters for all form data properties in the useForm hook. This allows consumers to access form fields reactively, improving reactivity and consistency in Svelte components. --- packages/svelte5/src/useForm.svelte.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/svelte5/src/useForm.svelte.ts b/packages/svelte5/src/useForm.svelte.ts index 5c4cb928d..246209a05 100644 --- a/packages/svelte5/src/useForm.svelte.ts +++ b/packages/svelte5/src/useForm.svelte.ts @@ -103,8 +103,16 @@ export default function useForm>( } } + // Create reactive getters for all form data properties + const formDataGetters = Object.keys(initialData).reduce((carry, key) => { + return { + ...carry, + get [key]() { return get(formData, key) } + } + }, {} as TForm) + const form: InertiaFormRunes = { - ...formData, + ...formDataGetters, get isDirty() { return isDirty }, get errors() { return errors }, get hasErrors() { return hasErrors }, From bc59e377552c85a09b2b613422ec3fb75414f31b Mon Sep 17 00:00:00 2001 From: Brodie <32996052+brodienguyen@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:24:46 +1000 Subject: [PATCH 035/112] refactor(remember): remove $ prefix from form references Update all references from $form to form in Remember.svelte to standardize variable usage and improve code clarity. --- .../Pages/Remember/FormHelper/Remember.svelte | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte b/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte index 73f8c49d7..28e485724 100644 --- a/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte +++ b/packages/svelte5/test-app/Pages/Remember/FormHelper/Remember.svelte @@ -10,35 +10,35 @@ let untracked = '' const submit = () => { - $form.post('/remember/form-helper/remember') + form.post('/remember/form-helper/remember') } const reset = () => { - $form.reset('handle').clearErrors('name') + form.reset('handle').clearErrors('name') }
- {#if $form.errors.name} - {$form.errors.name} + {#if form.errors.name} + {form.errors.name} {/if} - {#if $form.errors.handle} - {$form.errors.handle} + {#if form.errors.handle} + {form.errors.handle} {/if} - {#if $form.errors.remember} - {$form.errors.remember} + {#if form.errors.remember} + {form.errors.remember} {/if}