diff --git a/.github/workflows/es2020-compatibility.yml b/.github/workflows/es2020-compatibility.yml index 2cd3436d1..9ce783cd6 100644 --- a/.github/workflows/es2020-compatibility.yml +++ b/.github/workflows/es2020-compatibility.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - adapter: ['core', 'react', 'vue', 'svelte'] + adapter: ['core', 'react', 'vue', 'svelte', 'svelte5'] steps: - name: Checkout code diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index e3710503c..6b4189ba5 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - adapter: ['vue', 'react', 'svelte'] + adapter: ['vue', 'react', 'svelte', 'svelte5'] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c0022152c..efc2e67a0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - adapter: ['core', 'vue3', 'react', 'svelte'] + adapter: ['core', 'vue3', 'react', 'svelte', 'svelte5'] steps: - name: Checkout uses: actions/checkout@v4 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..70aaf97fb --- /dev/null +++ b/packages/svelte5/src/components/App.svelte @@ -0,0 +1,101 @@ + + + + + diff --git a/packages/svelte5/src/components/Deferred.svelte b/packages/svelte5/src/components/Deferred.svelte new file mode 100644 index 000000000..b2e00559b --- /dev/null +++ b/packages/svelte5/src/components/Deferred.svelte @@ -0,0 +1,42 @@ + + +{#if loaded} + {@render children?.()} +{:else} + {@render fallback?.()} +{/if} diff --git a/packages/svelte5/src/components/Form.svelte b/packages/svelte5/src/components/Form.svelte new file mode 100644 index 000000000..2b8aef749 --- /dev/null +++ b/packages/svelte5/src/components/Form.svelte @@ -0,0 +1,230 @@ + + +
+ {@render children?.({ + errors: slotErrors, + hasErrors: form.hasErrors, + processing: form.processing, + progress: form.progress, + wasSuccessful: form.wasSuccessful, + recentlySuccessful: form.recentlySuccessful, + isDirty, + clearErrors, + setError, + reset, + defaults, + submit, + data: form, + })} +
diff --git a/packages/svelte5/src/components/Link.svelte b/packages/svelte5/src/components/Link.svelte new file mode 100644 index 000000000..a61d6ca63 --- /dev/null +++ b/packages/svelte5/src/components/Link.svelte @@ -0,0 +1,145 @@ + + + + + {@render children?.()} + diff --git a/packages/svelte5/src/components/Render.svelte b/packages/svelte5/src/components/Render.svelte new file mode 100644 index 000000000..87f7b28ca --- /dev/null +++ b/packages/svelte5/src/components/Render.svelte @@ -0,0 +1,73 @@ + + + + +{#if component} + + {#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 new file mode 100644 index 000000000..53db37cde --- /dev/null +++ b/packages/svelte5/src/components/WhenVisible.svelte @@ -0,0 +1,99 @@ + + +{#if always || !loaded} + +{/if} + +{#if loaded} + {@render children?.()} +{:else if fallback} + {@render 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..e026ce399 --- /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.svelte' +export { default as useRemember } from './useRemember.svelte' 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.svelte.ts b/packages/svelte5/src/page.svelte.ts new file mode 100644 index 000000000..71178f398 --- /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 new file mode 100644 index 000000000..ed08fecd3 --- /dev/null +++ b/packages/svelte5/src/page.ts @@ -0,0 +1 @@ +export { page as default, setPage } from './page.svelte' 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.svelte.ts b/packages/svelte5/src/usePrefetch.svelte.ts new file mode 100644 index 000000000..792448ded --- /dev/null +++ b/packages/svelte5/src/usePrefetch.svelte.ts @@ -0,0 +1,58 @@ +import { router, type VisitOptions } from '@inertiajs/core' +import { onDestroy, onMount } from 'svelte' + +export default function usePrefetch(options: VisitOptions = {}) { + let isPrefetched = $state(false) + let isPrefetching = $state(false) + let lastUpdatedAt = $state(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 = cached !== null + isPrefetching = inFlight !== null + lastUpdatedAt = cached?.staleTimestamp || null + + let removePrefetchedListener: () => void + let removePrefetchingListener: () => void + + onMount(() => { + removePrefetchingListener = router.on('prefetching', ({ detail }) => { + if (detail.visit.url.pathname === window.location.pathname) { + isPrefetching = true + } + }) + + removePrefetchedListener = router.on('prefetched', ({ detail }) => { + if (detail.visit.url.pathname === window.location.pathname) { + isPrefetched = true + isPrefetching = false + } + }) + }) + + onDestroy(() => { + if (removePrefetchedListener) { + removePrefetchedListener() + } + + if (removePrefetchingListener) { + removePrefetchingListener() + } + }) + + return { + get isPrefetched() { + return isPrefetched + }, + get isPrefetching() { + return isPrefetching + }, + get lastUpdatedAt() { + return lastUpdatedAt + }, + flush() { + router.flush(window.location.pathname, options) + }, + } +} diff --git a/packages/svelte5/src/useRemember.svelte.ts b/packages/svelte5/src/useRemember.svelte.ts new file mode 100644 index 000000000..a9feb2fb4 --- /dev/null +++ b/packages/svelte5/src/useRemember.svelte.ts @@ -0,0 +1,12 @@ +import { router } from '@inertiajs/core' + +export default function useRemember(initialState: State, key?: string): State { + const restored = router.restore(key) as State | undefined + const state = $state(restored !== undefined ? restored : initialState) + + $effect(() => { + router.remember(state, key) + }) + + return state +} 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..45a78479a --- /dev/null +++ b/packages/svelte5/test-app/Layouts/NestedLayout.svelte @@ -0,0 +1,27 @@ + + +
+ Nested Layout + {createdAt} +
+ {@render children?.()} +
+
diff --git a/packages/svelte5/test-app/Layouts/Prefetch.svelte b/packages/svelte5/test-app/Layouts/Prefetch.svelte new file mode 100644 index 000000000..2c5fd923d --- /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..3d9fe18d2 --- /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..3113a1d0d --- /dev/null +++ b/packages/svelte5/test-app/Layouts/SiteLayout.svelte @@ -0,0 +1,27 @@ + + +
+ Site Layout + {createdAt} +
+ {@render children?.()} +
+
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..2af8e1b5d --- /dev/null +++ b/packages/svelte5/test-app/Pages/Article.svelte @@ -0,0 +1,97 @@ + + +

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..6b2ce6e57 --- /dev/null +++ b/packages/svelte5/test-app/Pages/ClientSideVisit/Page1.svelte @@ -0,0 +1,69 @@ + + +
+
{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..4184aef83 --- /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..cf0192a51 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeepMergeProps.svelte @@ -0,0 +1,43 @@ + + +
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..938ee0f56 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/InstantReload.svelte @@ -0,0 +1,26 @@ + + + +
{foo?.text}
+ {#snippet fallback()} +
Loading foo...
+ {/snippet} +
+ + +
{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 new file mode 100644 index 000000000..775286c5e --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/ManyGroups.svelte @@ -0,0 +1,56 @@ + + + + {foo?.text} + {#snippet fallback()} +
Loading foo...
+ {/snippet} +
+ + + {bar?.text} + {#snippet fallback()} +
Loading bar...
+ {/snippet} +
+ + + {baz?.text} + {#snippet fallback()} +
Loading baz...
+ {/snippet} +
+ + + {qux?.text} + {#snippet fallback()} +
Loading qux...
+ {/snippet} +
+ + + {quux?.text} + {#snippet fallback()} +
Loading quux...
+ {/snippet} +
+ +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..94e844449 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page1.svelte @@ -0,0 +1,22 @@ + + + + {foo?.text} + {#snippet fallback()} +
Loading foo...
+ {/snippet} +
+ + + {bar?.text} + {#snippet fallback()} +
Loading bar...
+ {/snippet} +
+ +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..bb878f1b0 --- /dev/null +++ b/packages/svelte5/test-app/Pages/DeferredProps/Page2.svelte @@ -0,0 +1,26 @@ + + + + {baz} + {#snippet fallback()} +
Loading baz...
+ {/snippet} +
+ + + {qux} + {#snippet fallback()} +
Loading qux...
+ {/snippet} +
+ + + both {baz} and {qux} + {#snippet fallback()} +
Loading baz and qux...
+ {/snippet} +
diff --git a/packages/svelte5/test-app/Pages/Dump.svelte b/packages/svelte5/test-app/Pages/Dump.svelte new file mode 100644 index 000000000..04082edbf --- /dev/null +++ b/packages/svelte5/test-app/Pages/Dump.svelte @@ -0,0 +1,42 @@ + + +
+
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..f6fb18d31 --- /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..bf6ff236f --- /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..f7a9eacb8 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/DisableWhileProcessing.svelte @@ -0,0 +1,22 @@ + + +
+

Form Disable While Processing Test

+ +
+ {#snippet children({ errors })} +
+ + {#if errors.name} +
{errors.name}
+ {/if} +
+ + + {/snippet} +
+
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..77fdb1ae8 --- /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..ff7253ec0 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Elements.svelte @@ -0,0 +1,112 @@ + + +
+ {#snippet children({ isDirty })} +

Form Elements

+ +
+ {#if isDirty}Form is dirty{:else}Form is clean{/if} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ + +
+ + +
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+ +
+ + + + {/snippet} +
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..e72083d4c --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/EmptyAction.svelte @@ -0,0 +1,20 @@ + + +
+

Form Empty Action Test

+ +
+ {#snippet children({ errors })} +
+ + {#if errors.name} +
{errors.name}
+ {/if} +
+ + + {/snippet} +
+
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..352560d57 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Errors.svelte @@ -0,0 +1,47 @@ + + +
+ {#snippet children({ errors, hasErrors, setError, clearErrors })} +

Form Errors

+ + {#if hasErrors} +
Form has errors
+ {:else} +
No errors
+ {/if} + +
+ + +
{errors.name || ''}
+
+ +
+ + +
{errors.handle || ''}
+
+ +
+ + + + +
+ + + {/snippet} +
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..596d545d3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Events.svelte @@ -0,0 +1,121 @@ + + +
+ {#snippet children({ processing, progress, wasSuccessful, recentlySuccessful })} +

Form Events & State

+ +
+ Events: {events.join(',')} +
+ +
+ Processing: {String(processing)} +
+ +
+ Progress: + {progress?.percentage || 0} + +
+ +
+ Was successful: {String(wasSuccessful)} +
+ +
+ Recently successful: {String(recentlySuccessful)} +
+ +
+ +
+ +
+ + + + + +
+ {/snippet} +
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..403b4c518 --- /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..9649fcba2 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/InvalidateTags.svelte @@ -0,0 +1,31 @@ + + +
+ + +
+

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..c0c489677 --- /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..4af2811f5 --- /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..74168b3dc --- /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..20cd76adf --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/Ref.svelte @@ -0,0 +1,69 @@ + + +
+

Form Ref Test

+ +
+ {#snippet children({ isDirty, errors, hasErrors })} + +
Form is {isDirty ? 'dirty' : 'clean'}
+ {#if hasErrors} +
Form has errors
+ {/if} + {#if errors.name} +
{errors.name}
+ {/if} + +
+ +
+ +
+ +
+ +
+ +
+ {/snippet} +
+ +
+ + + + + + +
+
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..03b7d59be --- /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..d883d0eed --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnError.svelte @@ -0,0 +1,21 @@ + + +
+ {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + + {/snippet} +
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..f4d4471d8 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnErrorFields.svelte @@ -0,0 +1,21 @@ + + +
+ {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
+ +
+ + +

{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 new file mode 100644 index 000000000..73dadab25 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccess.svelte @@ -0,0 +1,21 @@ + + +
+ {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
+ +
+ + +

{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 new file mode 100644 index 000000000..a7f0256dd --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/ResetAttributes/ResetOnSuccessFields.svelte @@ -0,0 +1,21 @@ + + +
+ {#snippet children({ errors })} +
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + + {/snippet} +
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..2fa38549e --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SetDefaultsOnSuccess.svelte @@ -0,0 +1,23 @@ + + +
+ {#snippet children({ isDirty, errors })} +

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

+ +
+ + +

{errors.name || ''}

+
+ +
+ + +

{errors.email || ''}

+
+ + + {/snippet} +
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..8acbd6a03 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Defaults.svelte @@ -0,0 +1,33 @@ + + +
+

OnSubmitComplete Defaults Test

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

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

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

{errors.name}

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

{errors.email}

+ {/if} +
+ +
+ +
+ {/snippet} +
+
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..c06fed224 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Redirect.svelte @@ -0,0 +1,22 @@ + + +
+

Form Empty Action Test

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

{errors.name}

+ {/if} +
+ +
+ +
+ {/snippet} +
+
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..26e650dc3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormComponent/SubmitComplete/Reset.svelte @@ -0,0 +1,29 @@ + + +
+

OnSubmitComplete Reset Test

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

{errors.name}

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

{errors.email}

+ {/if} +
+ +
+ +
+ {/snippet} +
+
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..63045a191 --- /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..436a9ed3e --- /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..9119f895b --- /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..0ef942155 --- /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..824747fb3 --- /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..75f363527 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Errors.svelte @@ -0,0 +1,77 @@ + + +
+ + {#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..74b7d3b5e --- /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..527b36471 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/Methods.svelte @@ -0,0 +1,50 @@ + + +
+ + + + + + + + + +
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..a39b0a1f3 --- /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..b0962b486 --- /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..ce67f1845 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/Child.svelte @@ -0,0 +1,16 @@ + + +

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..1b8f0149d --- /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..a43d2fef8 --- /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..9e78f678c --- /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..8f0f1f958 --- /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..e17e17340 --- /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..63d410c18 --- /dev/null +++ b/packages/svelte5/test-app/Pages/FormHelper/TypeScript/OptionalProps.svelte @@ -0,0 +1,24 @@ + 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..11ad2ebeb --- /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..c235c658f --- /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..98b1ccca3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/History/Page.svelte @@ -0,0 +1,16 @@ + + +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..424f961e7 --- /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..3ce38061a --- /dev/null +++ b/packages/svelte5/test-app/Pages/Home.svelte @@ -0,0 +1,50 @@ + + +
+ 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..47eb071cc --- /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..7da654f03 --- /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..bb175dafe --- /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..e57e136d7 --- /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..66fe8dabc --- /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..e9bf23e50 --- /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..0536d4ddd --- /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..7c6b3aa50 --- /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..d7874af8b --- /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..bcd7503d0 --- /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..077714235 --- /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..eaaecf153 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Links/PartialReloads.svelte @@ -0,0 +1,23 @@ + + +
+ 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..f6bb66673 --- /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..ff2a48a78 --- /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..2cce1a032 --- /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..3a37cf4e5 --- /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..f8473f6ec --- /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..abce0519b --- /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..bb46a893a --- /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..3c57eecc2 --- /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..a0a20e32e --- /dev/null +++ b/packages/svelte5/test-app/Pages/MatchPropsOnKey.svelte @@ -0,0 +1,59 @@ + + +
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..eb1cfd72d --- /dev/null +++ b/packages/svelte5/test-app/Pages/MergeProps.svelte @@ -0,0 +1,22 @@ + + +
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..276797f14 --- /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..f8d1f649e --- /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..6c19a0ad6 --- /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..340f84ed6 --- /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..2e1084e49 --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageA.svelte @@ -0,0 +1,22 @@ + + + + +
+ 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..28776c5cf --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Nested/PageB.svelte @@ -0,0 +1,22 @@ + + + + +
+ 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..d536b337f --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageA.svelte @@ -0,0 +1,21 @@ + + + + +
+ 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..e4b6e5d3b --- /dev/null +++ b/packages/svelte5/test-app/Pages/PersistentLayouts/Shorthand/Simple/PageB.svelte @@ -0,0 +1,21 @@ + + + + +
+ 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..636ed6b09 --- /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..3e6be609e --- /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..ad3b1ae46 --- /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..aaadc19b5 --- /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..83b442a82 --- /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..1506f8fd7 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Page.svelte @@ -0,0 +1,12 @@ + + + + +
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..3c82677a3 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/SWR.svelte @@ -0,0 +1,12 @@ + + + + +
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..8547a57c2 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Prefetch/Tags.svelte @@ -0,0 +1,76 @@ + + +
+ +
+ + + +
+ +
+

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..b67011b47 --- /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..8d4ce3400 --- /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..bb1b1bda4 --- /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..b622bc8e0 --- /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..69e8bd086 --- /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..bdbcd0cc2 --- /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..28e485724 --- /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..8e23671a7 --- /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..6c0372946 --- /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..dcdad5307 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Svelte/PropsAndPageStore.svelte @@ -0,0 +1,40 @@ + + +
+ +

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..f2bd52c5d --- /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..25988417e --- /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..8980152b7 --- /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..f0c1272d9 --- /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..986e63e55 --- /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..652d4278d --- /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..0e422ba69 --- /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..12d919eac --- /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..dd05ab28f --- /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..e66626766 --- /dev/null +++ b/packages/svelte5/test-app/Pages/Visits/PartialReloads.svelte @@ -0,0 +1,125 @@ + + +
+ 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..2a28500a6 --- /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..f36aa7644 --- /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..1275a4fc8 --- /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..fea374d50 --- /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..d1f1924d5 --- /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..89cf42380 --- /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..95d2c956c --- /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..46e0faf57 --- /dev/null +++ b/packages/svelte5/test-app/Pages/WhenVisible.svelte @@ -0,0 +1,68 @@ + + +
+ + {#snippet fallback()} +
Loading first one...
+ {/snippet} + {#snippet children()} +
First one is visible!
+ {/snippet} +
+
+ +
+ + {#snippet fallback()} +
Loading second one...
+ {/snippet} + {#snippet children()} +
Second one is visible!
+ {/snippet} +
+
+ +
+ + {#snippet fallback()} +
Loading third one...
+ {/snippet} + {#snippet children()} +
Third one is visible!
+ {/snippet} +
+
+ +
+ + {#snippet fallback()} +
Loading fourth one...
+ {/snippet} +
+
+ +
+ + {#snippet fallback()} +
Loading fifth one...
+ {/snippet} + {#snippet children()} +
Count is now {count}
+ {/snippet} +
+
diff --git a/packages/svelte5/test-app/app.ts b/packages/svelte5/test-app/app.ts new file mode 100644 index 000000000..fed786a08 --- /dev/null +++ b/packages/svelte5/test-app/app.ts @@ -0,0 +1,22 @@ +import { createInertiaApp, type ResolvedComponent, router } from '@inertiajs/svelte5' +import { mount } from '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 }) { + return mount(App as any, { 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..0de13c4d9 --- /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/vite-plugin-svelte": "^6.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/svelte5": "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..efd9da421 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/svelte5': + specifier: workspace:* + version: link:.. + devDependencies: + '@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)) + '@tsconfig/svelte': + specifier: ^5.0.4 + version: 5.0.5 + nodemon: + specifier: ^3.0.0 + version: 3.1.10 + svelte: + specifier: ^5.0.0 + version: 5.39.4 + svelte-check: + specifier: ^4.1.0 + version: 4.3.1(picomatch@4.0.3)(svelte@5.39.4)(typescript@5.9.2) + 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/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]) diff --git a/tests/events.spec.ts b/tests/events.spec.ts index aa72827ad..f0673848f 100644 --- a/tests/events.spec.ts +++ b/tests/events.spec.ts @@ -376,7 +376,10 @@ test.describe('Events', () => { }) test('can delay onFinish from firing by returning a promise (link)', async ({ page }) => { - 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', + ) await page.getByRole('button', { exact: true, name: 'Error Event Link (delaying onFinish w/ Promise)' }).click() @@ -434,7 +437,10 @@ test.describe('Events', () => { }) test('can delay onFinish from firing by returning a promise (link)', async ({ page }) => { - 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', + ) await page .getByRole('button', { exact: true, name: 'Success Event Link (delaying onFinish w/ Promise)' }) diff --git a/tests/form-helper.spec.ts b/tests/form-helper.spec.ts index 0a232d595..d3cd8867f 100644 --- a/tests/form-helper.spec.ts +++ b/tests/form-helper.spec.ts @@ -321,7 +321,7 @@ test.describe('Form Helper', () => { }) test('form should be dirty after setting the defaults', async ({ page }) => { - test.skip(process.env.PACKAGE === 'svelte', 'Skipping Svelte for now') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Skipping Svelte for now') await expect(page.getByText('Form is clean')).toBeVisible() await page.getByRole('button', { name: 'Defaults', exact: true }).click() @@ -331,7 +331,7 @@ test.describe('Form Helper', () => { }) test('form should be clean after setting data and then setting the defaults', async ({ page }) => { - test.skip(process.env.PACKAGE === 'svelte', 'Skipping Svelte for now') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Skipping Svelte for now') await expect(page.getByText('Form is clean')).toBeVisible() await page.getByRole('button', { name: 'Data and Defaults' }).click() diff --git a/tests/head.spec.ts b/tests/head.spec.ts index 7552ba80b..b48881096 100644 --- a/tests/head.spec.ts +++ b/tests/head.spec.ts @@ -1,7 +1,10 @@ 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..da3131146 100644 --- a/tests/links.spec.ts +++ b/tests/links.spec.ts @@ -821,7 +821,10 @@ 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 +901,10 @@ 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') diff --git a/tests/manual-visits.spec.ts b/tests/manual-visits.spec.ts index 506943404..9075a17b0 100644 --- a/tests/manual-visits.spec.ts +++ b/tests/manual-visits.spec.ts @@ -17,7 +17,7 @@ test('visits a different page', async ({ page }) => { }) test('can make a location visit', async ({ page }) => { - test.skip(process.env.PACKAGE === 'svelte', 'Skipping for now until we diagnose') + test.skip(process.env.PACKAGE === 'svelte' || process.env.PACKAGE === 'svelte5', 'Skipping for now until we diagnose') pageLoads.watch(page, 2) await page.goto('/visits/location')