From dade2932ce1bf62ddce42eebc586de5e2b467a04 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Wed, 19 Jun 2024 13:48:00 +0300 Subject: [PATCH 01/24] docs: Except & Always methods --- docs/guide/partial-reloads.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/guide/partial-reloads.md b/docs/guide/partial-reloads.md index 40b7470..b43e89f 100644 --- a/docs/guide/partial-reloads.md +++ b/docs/guide/partial-reloads.md @@ -56,9 +56,6 @@ router.visit(url, { ## Except certain props -> [!WARNING] -> The `except` option is not yet supported by the Inertia Rails. - :::tabs key:frameworks == Vue 2 @@ -215,6 +212,18 @@ class UsersController < ApplicationController end ``` +On the inverse, you can use the `InertiaRails.always` method to specify that a prop should always be included, even if it has not been explicitly required in a partial reload. + +```ruby +class UsersController < ApplicationController + def index + render inertia: 'Users/Index', props: { + users: InertiaRails.always(User.all), + } + end +end +``` + Here's a summary of each approach: ```ruby @@ -235,6 +244,11 @@ class UsersController < ApplicationController # OPTIONALLY included on partial reloads # ONLY evaluated when needed users: InertiaRails.lazy(-> { User.all }), + + # ALWAYS included on standard visits + # ALWAYS included on partial reloads + # ALWAYS evaluated + users: InertiaRails.always(User.all), } end end From 9883ef5e59d7bfcb64f28e08d37fd212e3bd40cb Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 09:40:10 +0300 Subject: [PATCH 02/24] docs: update the protocol page --- docs/guide/the-protocol.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/guide/the-protocol.md b/docs/guide/the-protocol.md index 1145d21..a2bc006 100644 --- a/docs/guide/the-protocol.md +++ b/docs/guide/the-protocol.md @@ -66,7 +66,9 @@ X-Inertia: true } }, "url": "/events/80", - "version": "c32b8e4965f418ad16eaebba1d4e960f" + "version": "c32b8e4965f418ad16eaebba1d4e960f", + "encryptHistory": true, + "clearHistory": false } ``` @@ -78,6 +80,8 @@ Inertia shares data between the server and client via a page object. This object 2. `props`: The page props (data). 3. `url`: The page URL. 4. `version`: The current asset version. +5. `encryptHistory`: Whether or not to encrypt the current page's history state. +6. `clearHistory`: Whether or not to clear any encrypted history state. On standard full page visits, the page object is JSON encoded into the `data-page` attribute in the root `
`. On Inertia visits, the page object is returned as the JSON payload. From f0f1f278b8d13b9f6f1d2e4a42b6e86bb51f4c91 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 09:52:49 +0300 Subject: [PATCH 03/24] docs: drop Vue 2 --- docs/guide/client-side-setup.md | 55 +----- docs/guide/code-splitting.md | 30 +--- docs/guide/csrf-protection.md | 14 +- docs/guide/error-handling.md | 41 +---- docs/guide/events.md | 250 +++------------------------ docs/guide/file-uploads.md | 68 +------- docs/guide/forms.md | 223 ++---------------------- docs/guide/links.md | 130 ++------------ docs/guide/manual-visits.md | 255 +++------------------------- docs/guide/pages.md | 169 +----------------- docs/guide/partial-reloads.md | 44 +---- docs/guide/progress-indicators.md | 44 +---- docs/guide/remembering-state.md | 91 +--------- docs/guide/scroll-management.md | 42 +---- docs/guide/server-side-rendering.md | 44 +---- docs/guide/shared-data.md | 47 +---- docs/guide/title-and-meta.md | 103 +---------- docs/guide/validation.md | 64 +------ 18 files changed, 110 insertions(+), 1604 deletions(-) diff --git a/docs/guide/client-side-setup.md b/docs/guide/client-side-setup.md index 216f979..0309fbd 100644 --- a/docs/guide/client-side-setup.md +++ b/docs/guide/client-side-setup.md @@ -10,13 +10,7 @@ Once you have your [server-side framework configured](/guide/server-side-setup.m First, install the Inertia client-side adapter corresponding to your framework of choice. :::tabs key:frameworks -== Vue 2 - -```shell -npm install @inertiajs/vue2 vue@^2 -``` - -== Vue 3 +== Vue ```shell npm install @inertiajs/vue3 vue @@ -41,29 +35,7 @@ npm install @inertiajs/svelte svelte Next, update your main JavaScript file to boot your Inertia app. To accomplish this, we'll initialize the client-side framework with the base Inertia component. :::tabs key:frameworks -== Vue 2 - -```js -// frontend/entrypoints/inertia.js -import Vue from 'vue' -import { createInertiaApp } from '@inertiajs/vue2' - -createInertiaApp({ - resolve: (name) => { - const pages = import.meta.glob('../pages/**/*.vue', { eager: true }) - return pages[`../pages/${name}.vue`] - }, - setup({ el, App, props, plugin }) { - Vue.use(plugin) - - new Vue({ - render: (h) => h(App, props), - }).$mount(el) - }, -}) -``` - -== Vue 3 +== Vue ```js // frontend/entrypoints/inertia.js @@ -129,28 +101,7 @@ The `setup` callback receives everything necessary to initialize the client-side The `resolve` callback tells Inertia how to load a page component. It receives a page name (string), and returns a page component module. How you implement this callback depends on which bundler (Vite or Webpack) you're using. :::tabs key:frameworks -== Vue 2 - -```js -// Vite -// frontend/entrypoints/inertia.js -createInertiaApp({ - resolve: name => { - const pages = import.meta.glob('../pages/**/*.vue', {eager: true}) - return pages[`../pages/${name}.vue`] - }, - // ... -}) - -// Webpacker/Shakapacker -// javascript/packs/inertia.js -createInertiaApp({ - resolve: name => require(`../pages/${name}`), - // ... -}) -``` - -== Vue 3 +== Vue ```js // Vite diff --git a/docs/guide/code-splitting.md b/docs/guide/code-splitting.md index c664251..e18a2de 100644 --- a/docs/guide/code-splitting.md +++ b/docs/guide/code-splitting.md @@ -11,22 +11,7 @@ To enable code splitting you'll need to tweak the resolve callback in your `crea Vite enables code splitting (or lazy-loading as they call it) by default when using their `import.meta.glob()` function, so simply omit the `{ eager: true }` option, or set it to false, to disable eager loading. :::tabs key:frameworks -== Vue 2 - -```js -// frontend/entrypoints/inertia.js -createInertiaApp({ - resolve: name => { - const pages = import.meta.glob('../pages/**/*.vue', {eager: true}) // [!code --] - return pages[`../pages/${name}.vue`] // [!code --] - const pages = import.meta.glob('../pages/**/*.vue') // [!code ++] - return pages[`../pages/${name}.vue`]() // [!code ++] - }, - //... -}) -``` - -== Vue 3 +== Vue ```js // frontend/entrypoints/inertia.js @@ -95,18 +80,7 @@ Next, create a `.babelrc` file in your project with the following configuration: Finally, update the `resolve` callback in your app's initialization code to use `import` instead of `require`. :::tabs key:frameworks -== Vue 2 - -```js -// javascript/packs/inertia.js -createInertiaApp({ - resolve: name => require(`../pages/${name}`), // [!code ii] - resolve: name => import(`../pages/${name}`), // [!code ++] - //... -}) -``` - -== Vue 3 +== Vue ```js // javascript/packs/inertia.js diff --git a/docs/guide/csrf-protection.md b/docs/guide/csrf-protection.md index 81df703..8b961d5 100644 --- a/docs/guide/csrf-protection.md +++ b/docs/guide/csrf-protection.md @@ -7,19 +7,7 @@ Inertia's Rails adapter automatically includes the proper CSRF token when making However, if you need to handle CSRF protection manually, one approach is to include the CSRF token as a prop on every response. You can then use the token when making Inertia requests. :::tabs key:frameworks -== Vue 2 - -```js -import { router } from '@inertiajs/vue2' - -router.post('/users', { - _token: this.$page.props.csrf_token, - name: 'John Doe', - email: 'john.doe@example.com', -}) -``` - -== Vue 3 +== Vue ```js import { router, usePage } from '@inertiajs/vue3' diff --git a/docs/guide/error-handling.md b/docs/guide/error-handling.md index 05a19a7..8d1dbb0 100644 --- a/docs/guide/error-handling.md +++ b/docs/guide/error-handling.md @@ -31,46 +31,7 @@ end You may have noticed we're returning an `Error` page component in the example above. You'll need to actually create this component, which will serve as the generic error page for your application. Here's an example error component you can use as a starting point. :::tabs key:frameworks -== Vue 2 - -```vue - - - -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -If you're using Vue 2.7 or Vue 3, you can alternatively use the [defineOptions plugin](https://vue-macros.dev/macros/define-options.html) to define a layout within ` -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue -``` - -== Vue 3 +== Vue ```vue @@ -362,15 +281,7 @@ export default AppHead Once you have created the custom component, you may simply start using the custom component in your pages. :::tabs key:frameworks -== Vue 2 - -```vue -import AppHead from './AppHead' - - -``` - -== Vue 3 +== Vue ```vue import AppHead from './AppHead' diff --git a/docs/guide/validation.md b/docs/guide/validation.md index 487720a..9a1e086 100644 --- a/docs/guide/validation.md +++ b/docs/guide/validation.md @@ -39,53 +39,7 @@ In order for your server-side validation errors to be available client-side, you Since validation errors are made available client-side as page component props, you can conditionally display them based on their existence. Remember, when using Rails server adapter, the `errors` prop will automatically be available to your page. :::tabs key:frameworks -== Vue 2 - -```vue - - - -``` - -> [!NOTE] -> When using the Vue adapters, you may also access the errors via the `$page.props.errors` object. - -== Vue 3 +== Vue ```vue + + +``` + +== React + +```jsx +import { Deferred } from '@inertiajs/react' + +export default () => ( +
Loading...
}> + +
+) +``` + +== Svelte + +```svelte + + + + +
Loading...
+
+ {permissions} +
+``` +::: + +If you need to wait for multiple deferred props to become available, you can specify an array to the `data` prop. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Deferred } from '@inertiajs/react' + +export default () => ( +
Loading...
}> + +
+) +``` + +== Svelte + +```svelte + + + + +
Loading...
+
+ +
+``` +::: From 2f80a7d491746c49b154e5203e9c7cf3fa8e09fe Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 10:38:49 +0300 Subject: [PATCH 06/24] docs: add history encryption page --- docs/guide/history-encryption.md | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 docs/guide/history-encryption.md diff --git a/docs/guide/history-encryption.md b/docs/guide/history-encryption.md new file mode 100644 index 0000000..a0c90e0 --- /dev/null +++ b/docs/guide/history-encryption.md @@ -0,0 +1,55 @@ +# History encryption + +Imagine a scenario where your user is authenticated, browses privileged information on your site, then logs out. If they press the back button, they can still see the privileged information that is stored in the window's history state. This is a security risk. To prevent this, Inertia.js provides a history encryption feature. + +## How it works + +When you instruct Inertia to encrypt your app's history, it uses the browser's built-in [`crypto` api](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) to encrypt the current page's data before pushing it to the history state. We store the corresponding key in the browser's session storage. When the user navigates back to a page, we decrypt the data using the key stored in the session storage. + +Once you instruct Inertia to clear your history state, we simply clear the existing key from session storage roll a new one. If we attempt to decrypt the history state with the new key, it will fail an Inertia will make a fresh request back to your server for the page data. + +## Opting in + +History encryption is an opt-in feature. There are several methods for enabling it: + +### Global encryption + +If you'd like to enable history encryption globally, set the `history_encrypted` config value to `true`. + +You are able to opt out of encryption on specific pages by passing `false` to the `encrypt_history` option: + +```ruby +render inertia: 'Homepage', props: {}, encrypt_history: false +``` + +### Per-request encryption + +To encrypt the history of an individual request, simply pass `true` to the `encrypt_history` option: + +```ruby +render inertia: 'Dashboard', props: {}, encrypt_history: true +``` + +### Controller-level encryption + +You can also enable history encryption for all actions in a controller by setting the `history_encrypted` config value in the controller: + +```ruby +class DashboardController < ApplicationController + inertia_config(history_encrypted: true) + + # ... +end +``` + +## Clearing history + +To clear the history state, you can pass the `clear_history` option to the `render` method: + +```ruby +render inertia: 'Dashboard', props: {}, clear_history: true +``` + +Once the response has rendered on the client, the encryption key will be rotated, rendering the previous history state unreadable. + +You can also clear history on the client site by calling `router.clearHistory()`. From f1cdb56a1e5f22e5726f68c0ca2a17e82993516b Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 10:55:04 +0300 Subject: [PATCH 07/24] docs: add load when visible page --- docs/guide/load-when-visible.md | 251 ++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 docs/guide/load-when-visible.md diff --git a/docs/guide/load-when-visible.md b/docs/guide/load-when-visible.md new file mode 100644 index 0000000..4a97843 --- /dev/null +++ b/docs/guide/load-when-visible.md @@ -0,0 +1,251 @@ +# Load when visible + +Inertia supports lazy loading data on scroll using the Intersection Observer API. It provides the `WhenVisible` component as a convenient way to load data when an element becomes visible in the viewport. + +The `WhenVisible` component accepts a `data` prop that specifies the key of the prop to load. It also accepts a `fallback` prop that specifies a component to render while the data is loading. The `WhenVisible` component should wrap the component that depends on the data. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { WhenVisible } from '@inertiajs/react' + +export default () => ( +
Loading...
}> + +
+) +``` + +== Svelte + +```svelte + + + + +
Loading...
+
+ {permissions} +
+``` +::: + +If you'd like to load multiple props when an element becomes visible, you can provide an array to the `data` prop. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { WhenVisible } from '@inertiajs/react' + +export default () => ( +
Loading...
}> + +
+) +``` + +== Svelte + +```svelte + + + + +
Loading...
+
+ +
+``` +::: + +## Loading before visible + +If you'd like to start loading data before the element is visible, you can provide a value to the `buffer` prop. The buffer value is a number that represents the number of pixels before the element is visible. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { WhenVisible } from '@inertiajs/react' +export default () => ( +
Loading...
}> + +
+) +``` + +== Svelte + +```svelte + + + + +
Loading...
+
+ {permissions} +
+``` +::: + +In the above example, the data will start loading 500 pixels before the element is visible. + +By default, the `WhenVisible` component wraps the fallback template in a `div` element so it can ensure the element is visible in the viewport. If you want to customize the wrapper element, you can provide the `as` prop. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { WhenVisible } from '@inertiajs/react' + +export default () => ( + + + +) +``` + +== Svelte + +```svelte + + + + {products} + +``` +::: + +## Always trigger + +By default, the `WhenVisible` component will only trigger once when the element becomes visible. If you want to always trigger the data loading when the element is visible, you can provide the `always` prop. + +This is useful when you want to load data every time the element becomes visible, such as when the element is at the end of an infinite scroll list and you want to load more data. + +Note that if the data loading request is already in flight, the component will wait until it is finished to start the next request if the element is still visible in the viewport. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { WhenVisible } from '@inertiajs/react' + +export default () => ( + + + +) +``` + +== Svelte + +```svelte + + + + {products} + +``` +::: + From e764adf7561b90559d78926b90ff6d32128c064e Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 11:17:21 +0300 Subject: [PATCH 08/24] docs: add merging props page --- docs/guide/merging-props.md | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/guide/merging-props.md diff --git a/docs/guide/merging-props.md b/docs/guide/merging-props.md new file mode 100644 index 0000000..3c9cfb9 --- /dev/null +++ b/docs/guide/merging-props.md @@ -0,0 +1,70 @@ +# Merging props + +By default, Inertia overwrites props with the same name when reloading a page. However, there are instances, such as pagination or infinite scrolling, where that is not the desired behavior. In these cases, you can merge props instead of overwriting them. + +## Server side + +To specify that a prop should be merged, you can use the `merge` method on the prop value. + +```ruby +class UsersController < ApplicationController + include Pagy::Backend + + def index + _pagy, records = pagy(User.all) + + render inertia: 'Users/Index', props: { + results: InertiaRails.merge(-> { records }), + } + end +end +``` + +On the client side, Inertia detects that this prop should be merged. If the prop returns an array, it will append the response to the current prop value. If it's an object, it will merge the response with the current prop value. + +You can also combine [deferred props](/guide/deferred-props) with mergeable props to defer the loading of the prop and ultimately mark it as mergeable once it's loaded. + +```ruby +class UsersController < ApplicationController + include Pagy::Backend + + def index + render inertia: 'Users/Index', props: { + results: InertiaRails.defer(-> { pagy(User.all)[1] }).merge, + } + end +end +``` + +## Resetting props + +On the client side, you can indicate to the server that you would like to reset the prop. This is useful when you want to clear the prop value before merging new data, such as when the user enters a new search query on a paginated list. + +The `reset` request option accepts an array of the props keys you would like to reset. + +:::tabs key:frameworks +== Vue + +```vue +import { router } from '@inertiajs/vue3' + +router.reload({ reset: ['results'] }) +``` + +== React + +```jsx +import { router } from '@inertiajs/react' + +router.reload({ reset: ['results'] }) +``` + +== Svelte + +```svelte +import { router } from '@inertiajs/svelte' + +router.reload({ reset: ['results'] }) +``` + +::: From 198f2c1eaa4690e55269ee751195e92eaa09da64 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 11:26:02 +0300 Subject: [PATCH 09/24] docs: add upgrade guide page --- docs/guide/upgrade-guide.md | 59 +++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 docs/guide/upgrade-guide.md diff --git a/docs/guide/upgrade-guide.md b/docs/guide/upgrade-guide.md new file mode 100644 index 0000000..d54e1a9 --- /dev/null +++ b/docs/guide/upgrade-guide.md @@ -0,0 +1,59 @@ +# Upgrade guide for v2.0 + +> [!NOTE] +> Inertia.js v2.0 is still in beta and these docs are a work-in-progress. Please report bugs on +https://github.com/inertiajs/inertia https://github.com/inertiajs/inertia-rails and https://github.com/skryukov/inertia-rails_contrib + +## What's new + +Inertia.js v2.0 is a huge step forward for Inertia! The core library has been completely rewritten to architecturally support asynchronous requests, enabling a whole set of new features, including: + +- [Polling](/guide/polling) +- [Prefetching](/guide/prefetching) +- [Deferred props](/guide/deferred-props) +- [Infinite scrolling](/guide/merging-props) +- [Lazy loading data on scroll](/guide/load-when-visible) + +Additionally, for security sensitive projects, Inertia now offers a [history encryption API](/guide/history-encryption), allowing you to clear page data from history state when logging out of an application. + +## Upgrade dependencies +To upgrade to the Inertia.js v2.0 beta, first use npm to install the client-side adapter of your choice: + +:::tabs key:frameworks +== Vue + +```vue +npm install @inertiajs/vue3@next +``` + +== React + +```jsx +npm install @inertiajs/react@next +``` + +== Svelte + +```svelte +npm install @inertiajs/svelte@next +``` +::: + + +Next, upgrade the `inertia-rails` gem to use the `2.x` dev branch: + +```ruby +gem 'inertia_rails', github: 'inertiajs/inertia-rails', branch: '2.x' +``` + +## Breaking changes + +While a significant release, Inertia.js v2.0 doesn't introduce many breaking changes. Here's a list of all the breaking changes: + +### Dropped Vue 2 support + +The Vue 2 adapter has been removed. Vue 2 reached End of Life on December 3, 2023, so this felt like it was time. + +### Partial reloads are now async + +Previously partial reloads in Inertia were synchronous, just like all Inertia requests. In v2.0, partial reloads are now asynchronous. Generally this is desirable, but if you were relying on these requests being synchronous, you may need to adjust your code. From f136f3337d97fb6889697a9da98d04b86c54a00a Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 11:36:46 +0300 Subject: [PATCH 10/24] docs: add polling page --- docs/guide/polling.md | 171 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 docs/guide/polling.md diff --git a/docs/guide/polling.md b/docs/guide/polling.md new file mode 100644 index 0000000..d087ae2 --- /dev/null +++ b/docs/guide/polling.md @@ -0,0 +1,171 @@ +# Polling + +## Poll helper + +Polling your server for new information on the current page is common, so Inertia provides a poll helper designed to help reduce the amount of boilerplate code. In addition, the poll helper will automatically stop polling when the page is unmounted. + +The only required argument is the polling interval in milliseconds. + +:::tabs key:frameworks +== Vue + +```js +import { usePoll } from '@inertiajs/vue3' +usePoll(2000) +``` + +== React + +```js +import { usePoll } from '@inertiajs/react' +usePoll(2000) +``` + +== Svelte + +```js +import { usePoll } from '@inertiajs/svelte' +usePoll(2000) +``` +::: + +If you need to pass additional request options to the poll helper, you can pass any of the `router.reload` options as the second parameter. + + +:::tabs key:frameworks +== Vue + +```js +import { usePoll } from '@inertiajs/vue3' + +usePoll(2000, { + onStart() { + console.log('Polling request started') + }, + onFinish() { + console.log('Polling request finished') + } +}) +``` + +== React + +```js +import { usePoll } from '@inertiajs/react' + +usePoll(2000, { + onStart() { + console.log('Polling request started') + }, + onFinish() { + console.log('Polling request finished') + } +}) +``` + +== Svelte + +```js +import { usePoll } from '@inertiajs/svelte' + +usePoll(2000, { + onStart() { + console.log('Polling request started') + }, + onFinish() { + console.log('Polling request finished') + } +}) +``` +::: + +If you'd like more control over the polling behavior, the poll helper provides `stop` and `start` methods that allow you to manually start and stop polling. You can pass the `autoStart: false` option to the poll helper to prevent it from automatically starting polling when the component is mounted. + +:::tabs key:frameworks +== Vue + +```vue + + + + +``` + +== React + +```jsx +import { usePoll } from '@inertiajs/react' + +export default () => { + const { start, stop } = usePoll(2000, {}, { + autoStart: false, + }) + return ( +
+ + +
+ ) +} +``` + +== Svelte + +```svelte + + + + +``` +::: + + +## Throttling + +By default, the poll helper will throttle requests by 90% when the browser tab is in the background. If you'd like to disable this behavior, you can pass the `keepAlive` option to the poll helper. + +:::tabs key:frameworks +== Vue + +```js +import { usePoll } from '@inertiajs/vue3' + +usePoll(2000, {}, { + keepAlive: true, +}) +``` + +== React + +```js +import { usePoll } from '@inertiajs/react' + +usePoll(2000, {}, { + keepAlive: true, +}) +``` + +== Svelte + +```js +import { usePoll } from '@inertiajs/svelte' + +usePoll(2000, {}, { + keepAlive: true, +}) +``` +::: From 69146b295cc402fe088113aaeeec3bc4bfb4a6b4 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 11:53:03 +0300 Subject: [PATCH 11/24] docs: add prefetching page --- docs/guide/prefetching.md | 323 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 docs/guide/prefetching.md diff --git a/docs/guide/prefetching.md b/docs/guide/prefetching.md new file mode 100644 index 0000000..13b0291 --- /dev/null +++ b/docs/guide/prefetching.md @@ -0,0 +1,323 @@ +# Prefetching + +Inertia supports prefetching data for pages that are likely to be visited next. This can be useful for improving the perceived performance of your app by allowing the data to be fetched in the background while the user is still interacting with the current page. + +## Link prefetching + +To prefetch data for a page, you can use the `prefetch` method on the Inertia link component. By default, Inertia will prefetch the data for the page when the user hovers over the link after more than 75ms. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + Users +) +``` + +== Svelte + +```svelte + + +Users +``` +::: + +By default, data is cached for 30 seconds before being evicted. You can customize this behavior by passing a `cacheFor` prop to the `Link` component. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + <> + Users + Users + Users + +) +``` + +== Svelte + +```svelte + + +Users +Users +Users +``` +::: + +You can also start prefetching on `mousedown` by passing the `click` value to the `prefetch` prop. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + Users +) +``` + +== Svelte + +```svelte + + +Users +``` +::: + +If you're confident that the user will visit a page next, you can prefetch the data on mount as well. + + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + Users +) +``` + +== Svelte + +```svelte + + +Users +``` +::: + +You can also combine strategies by passing an array of values to the `prefetch` prop. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + Users +) +``` + +== Svelte + +```svelte + + +Users +``` +::: + +## Programmatic prefetching + +You can also prefetch data programmatically using `router.prefetch`. The signature is identical to `router.visit` with the exception of a third argument that allows you to specify prefetch options. + +When the `cacheFor` option is not specified, it defaults to 30 seconds. + +```js +router.prefetch( + '/users', + { method: 'get', data: { page: 2 } }, +) +router.prefetch( + '/users', + { method: 'get', data: { page: 2 } }, + { cacheFor: '1m' }, +) +``` +To make this even easier, Inertia offers a prefetch helper. This helper provides some additional insight into the request, such as the last updated timestamp and if the request is currently prefetching. + +:::tabs key:frameworks +== Vue + +```js +import { usePrefetch } from '@inertiajs/vue3' + +const { lastUpdatedAt, isPrefetching, isPrefetched } = usePrefetch( + '/users', + { method: 'get', data: { page: 2 } }, + { cacheFor: '1m' }, +) +``` + +== React + +```js +import { usePrefetch } from '@inertiajs/react' + +const { lastUpdatedAt, isPrefetching, isPrefetched } = usePrefetch( + '/users', + { method: 'get', data: { page: 2 } }, + { cacheFor: '1m' }, +) +``` + +== Svelte + +```js +import { usePrefetch } from '@inertiajs/svelte' + +const { lastUpdatedAt, isPrefetching, isPrefetched } = usePrefetch( + '/users', + { method: 'get', data: { page: 2 } }, + { cacheFor: '1m' }, +) +``` +::: + +## Flushing prefetch cache + +You can flush the prefetch cache by calling `router.flushAll`. This will remove all cached data for all pages. + +If you want to flush the cache for a specific page, you can pass the page URL and options to the `router.flush` method. + +Furthermore, if you are using the prefetch helper, it will return a `flush` method for you to use for that specific page. + +```js +// Flush all prefetch cache +router.flushAll() +// Flush cache for a specific page +router.flush( + '/users', + { method: 'get', data: { page: 2 } }, +) +const { flush } = usePrefetch( + '/users', + { method: 'get', data: { page: 2 } }, +) +// Flush cache for a specific page +flush() +``` + +## Stale while revalidate + +By default, Inertia will fetch a fresh copy of the data when the user visits the page if the cached data is older than the cache duration. You can customize this behavior by passing a tuple to the `cacheFor` prop. + +The first value in the array represents the number of seconds the cache is considered fresh, while the second value defines how long it can be served as stale data before fetching data from the server is necessary. + +:::tabs key:frameworks +== Vue + +```vue + + + +``` + +== React + +```jsx +import { Link } from '@inertiajs/react' + +export default () => ( + Users +) +``` + +== Svelte + +```svelte + + +Users +``` +::: + +### How it works + +If a request is made within the fresh period (before the first value), the cache is returned immediately without making a request to the server. + +If a request is made during the stale period (between the two values), the stale value is served to the user, and a request is made in the background to refresh the cached value. Once the value is returned, the data is merged into the page so the user has the most recent data. + +If a request is made after the second value, the cache is considered expired, and the value is fetched from the sever as a regular request. From 9696c4d4fa6236b8cd617db70032a8898dcc7540 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 16:42:24 +0300 Subject: [PATCH 12/24] Rename config value --- docs/guide/history-encryption.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide/history-encryption.md b/docs/guide/history-encryption.md index a0c90e0..17f6d61 100644 --- a/docs/guide/history-encryption.md +++ b/docs/guide/history-encryption.md @@ -14,7 +14,7 @@ History encryption is an opt-in feature. There are several methods for enabling ### Global encryption -If you'd like to enable history encryption globally, set the `history_encrypted` config value to `true`. +If you'd like to enable history encryption globally, set the `encrypt_history` config value to `true`. You are able to opt out of encryption on specific pages by passing `false` to the `encrypt_history` option: @@ -32,11 +32,11 @@ render inertia: 'Dashboard', props: {}, encrypt_history: true ### Controller-level encryption -You can also enable history encryption for all actions in a controller by setting the `history_encrypted` config value in the controller: +You can also enable history encryption for all actions in a controller by setting the `encrypt_history` config value in the controller: ```ruby class DashboardController < ApplicationController - inertia_config(history_encrypted: true) + inertia_config(encrypt_history: true) # ... end From 9c836f0255b0bf729ae7384ac74c1027d68e6ed3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 19:43:11 +0300 Subject: [PATCH 13/24] Fixes from original docs --- docs/guide/deferred-props.md | 4 ++-- docs/guide/history-encryption.md | 3 +++ docs/guide/load-when-visible.md | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/guide/deferred-props.md b/docs/guide/deferred-props.md index 17f6ef7..f8c0285 100644 --- a/docs/guide/deferred-props.md +++ b/docs/guide/deferred-props.md @@ -69,7 +69,7 @@ import { Deferred } from '@inertiajs/vue3' import { Deferred } from '@inertiajs/react' export default () => ( -
Loading...
}> + Loading...
}> ) @@ -118,7 +118,7 @@ import { Deferred } from '@inertiajs/vue3' import { Deferred } from '@inertiajs/react' export default () => ( -
Loading...
}> + Loading...}> ) diff --git a/docs/guide/history-encryption.md b/docs/guide/history-encryption.md index 17f6d61..db15fa8 100644 --- a/docs/guide/history-encryption.md +++ b/docs/guide/history-encryption.md @@ -8,6 +8,9 @@ When you instruct Inertia to encrypt your app's history, it uses the browser's b Once you instruct Inertia to clear your history state, we simply clear the existing key from session storage roll a new one. If we attempt to decrypt the history state with the new key, it will fail an Inertia will make a fresh request back to your server for the page data. +> [!NOTE] +> History encryption relies on `window.crypto.subtle` which is only available in secure environments (sites with SSL enabled). + ## Opting in History encryption is an opt-in feature. There are several methods for enabling it: diff --git a/docs/guide/load-when-visible.md b/docs/guide/load-when-visible.md index 4a97843..ca4c605 100644 --- a/docs/guide/load-when-visible.md +++ b/docs/guide/load-when-visible.md @@ -30,7 +30,7 @@ import { WhenVisible } from '@inertiajs/vue3' import { WhenVisible } from '@inertiajs/react' export default () => ( -
Loading...
}> + Loading...}> ) @@ -79,7 +79,7 @@ import { WhenVisible } from '@inertiajs/vue3' import { WhenVisible } from '@inertiajs/react' export default () => ( -
Loading...
}> + Loading...}> ) @@ -132,7 +132,7 @@ import { WhenVisible } from '@inertiajs/vue3' ```jsx import { WhenVisible } from '@inertiajs/react' export default () => ( -
Loading...
}> + Loading...}> ) From 7ea430bf897833b01715fd709745818154491808 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Thu, 10 Oct 2024 20:32:46 +0300 Subject: [PATCH 14/24] Add fork as tmp way to try v2 --- docs/guide/upgrade-guide.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide/upgrade-guide.md b/docs/guide/upgrade-guide.md index d54e1a9..b7a3f5c 100644 --- a/docs/guide/upgrade-guide.md +++ b/docs/guide/upgrade-guide.md @@ -39,11 +39,11 @@ npm install @inertiajs/svelte@next ``` ::: - -Next, upgrade the `inertia-rails` gem to use the `2.x` dev branch: +Next, upgrade the `inertia-rails` gem to use the unreleased version of the gem from [the PR branch](https://github.com/inertiajs/inertia-rails/pull/132): ```ruby -gem 'inertia_rails', github: 'inertiajs/inertia-rails', branch: '2.x' +# See the PR https://github.com/inertiajs/inertia-rails/pull/132 +gem 'inertia_rails', github: 'skryukov/inertia-rails', branch: 'v2/all' ``` ## Breaking changes From 025cccf12c7354799ec3096108baf0e7710565d1 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kryukov Date: Mon, 14 Oct 2024 08:57:29 +0300 Subject: [PATCH 15/24] docs: apply fixes from inertiajs/inertiajs.com#349 https://github.com/inertiajs/inertiajs.com/pull/349 --- docs/guide/pages.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/guide/pages.md b/docs/guide/pages.md index ac237af..eb1fb71 100644 --- a/docs/guide/pages.md +++ b/docs/guide/pages.md @@ -246,7 +246,8 @@ defineProps({ user: Object }) ``` -Alternatively use the [defineOptions plugin](https://vue-macros.dev/macros/define-options.html) to define a layout within `
Loading...
- {permissions} + + {#each permissions as permission} + + {/each}
``` + +== Svelte 5 + +```svelte + + + + {#snippet fallback()} +
Loading...
+ {/snippet} + + {#each permissions as permission} + + {/each} +
+``` + ::: If you need to wait for multiple deferred props to become available, you can specify an array to the `data` prop. @@ -124,19 +147,37 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 ```svelte
Loading...
+ + +
+``` + +== Svelte 5 + +```svelte + + + + {#snippet fallback()} +
Loading...
+ {/snippet} +
``` diff --git a/docs/guide/error-handling.md b/docs/guide/error-handling.md index 8d1dbb0..40c2713 100644 --- a/docs/guide/error-handling.md +++ b/docs/guide/error-handling.md @@ -62,7 +62,7 @@ const description = computed(() => { @@ -89,16 +89,16 @@ export default function ErrorPage({ status }) { return (
-

+

{status}: {title} -

+
{description}
) } ``` -== Svelte +== Svelte 4 ```svelte
-

{status}: {title}

+

{status}: {title}

{description}
``` +== Svelte 5 + +```svelte + + +
+

{titles[status]}

+
{description[status]}
+
+``` + ::: diff --git a/docs/guide/events.md b/docs/guide/events.md index 6e61496..8ce9f96 100644 --- a/docs/guide/events.md +++ b/docs/guide/events.md @@ -27,7 +27,7 @@ router.on('start', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -62,7 +62,7 @@ document.addEventListener('inertia:start', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -105,7 +105,7 @@ let removeStartEventListener = router.on('start', (event) => { removeStartEventListener() ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -149,7 +149,7 @@ useEffect(() => { }, []) ``` -== Svelte +== Svelte 4 ```js import { router } from '@inertiajs/svelte' @@ -162,6 +162,18 @@ onMount(() => { }) ``` +== Svelte 5 + +```js +import { router } from '@inertiajs/svelte' + +$effect(() => { + return router.on('start', (event) => { + console.log(`Starting a visit to ${event.detail.visit.url}`) + }) +}) +``` + ::: Alternatively, if you're using native browser events, you can remove the event listener using `removeEventListener()`. @@ -197,7 +209,7 @@ document.addEventListener('inertia:start', startEventListener) document.removeEventListener('inertia:start', startEventListener) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -243,7 +255,7 @@ router.on('before', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -280,7 +292,7 @@ router.on('before', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -319,7 +331,7 @@ router.on('before', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -354,7 +366,7 @@ router.on('before', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -391,7 +403,7 @@ router.on('start', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -430,7 +442,7 @@ router.on('progress', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -469,7 +481,7 @@ router.on('success', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -508,7 +520,7 @@ router.on('error', (errors) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -551,7 +563,7 @@ router.on('invalid', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -591,7 +603,7 @@ router.on('invalid', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -632,7 +644,7 @@ router.on('exception', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -670,7 +682,7 @@ router.on('exception', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -710,7 +722,7 @@ router.on('finish', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -749,7 +761,7 @@ router.on('navigate', (event) => { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' diff --git a/docs/guide/file-uploads.md b/docs/guide/file-uploads.md index f61c7d0..7fb58d3 100644 --- a/docs/guide/file-uploads.md +++ b/docs/guide/file-uploads.md @@ -27,7 +27,7 @@ router.post('/users', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -113,20 +113,20 @@ return ( ) ``` -== Svelte +== Svelte 4 ```svelte
@@ -141,6 +141,35 @@ function submit() {
``` +== Svelte 5 + +```svelte + + +
+ + $form.avatar = e.target.files[0]} /> + {#if $form.progress} + + {$form.progress.percentage}% + + {/if} + +
+``` + ::: This example uses the [Inertia form helper](/guide/forms.md) for convenience, since the form helper provides easy access to the current upload progress. However, you are free to submit your forms using [manual Inertia visits](/guide/manual-visits.md) as well. @@ -189,7 +218,7 @@ form.post(`/users/${user.id}`, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' diff --git a/docs/guide/forms.md b/docs/guide/forms.md index 514754c..5938210 100644 --- a/docs/guide/forms.md +++ b/docs/guide/forms.md @@ -27,10 +27,13 @@ function submit() {
+ + +
@@ -71,17 +74,51 @@ export default function Edit() { value={values.first_name} onChange={handleChange} /> + + + ) } ``` -== Svelte +== Svelte 4 + +```svelte + + +
+ + + + + + + + + + +
+``` + +== Svelte 5 ```svelte -
+ @@ -223,21 +261,21 @@ return ( ) ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte @@ -254,6 +292,38 @@ function submit() {
``` +== Svelte 5 + +```svelte + + +
+ + {#if $form.errors.email} +
{$form.errors.email}
+ {/if} + + {#if $form.errors.password} +
{$form.errors.password}
+ {/if} + Remember Me + +
+``` + ::: To submit the form, you may use the `get`, `post`, `put`, `patch` and `delete` methods. @@ -283,7 +353,7 @@ patch(url, options) destroy(url, options) ``` -== Svelte +== Svelte 4|Svelte 5 ```js $form.submit(method, url, options) @@ -319,7 +389,7 @@ onSuccess: () => reset('password'), }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js $form.post('/profile', { @@ -355,7 +425,7 @@ transform((data) => ({ })) ``` -== Svelte +== Svelte 4|Svelte 5 ```js $form @@ -385,7 +455,7 @@ const { processing } = useForm({ ... }) ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte @@ -416,7 +486,7 @@ const { progress } = useForm({ ... }) )} ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte {#if $form.progress} @@ -445,7 +515,7 @@ const { errors } = useForm({ ... }) {errors.email &&
{errors.email}
} ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte {#if $form.errors.email} @@ -483,7 +553,7 @@ clearErrors() clearErrors('field', 'anotherfield') ``` -== Svelte +== Svelte 4|Svelte 5 ```js // Clear all errors... @@ -526,7 +596,7 @@ setError({ }); ``` -== Svelte +== Svelte 4|Svelte 5 ```js // Set a single error @@ -571,7 +641,7 @@ reset() reset('field', 'anotherfield') ``` -== Svelte +== Svelte 4|Svelte 5 ```js // Reset the form... @@ -620,7 +690,7 @@ setDefaults({ }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js // Set the form's current values as the new defaults... @@ -655,7 +725,7 @@ const { isDirty } = useForm({ ... }) {isDirty &&
There are unsaved form changes.
} ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte {#if $form.isDirty} @@ -682,7 +752,7 @@ const { cancel } = useForm({ ... }) cancel() ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte $form.cancel() @@ -711,7 +781,7 @@ const form = useForm('CreateUser', data) const form = useForm(`EditUser:${user.id}`, data) ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { useForm } from '@inertiajs/svelte' diff --git a/docs/guide/links.md b/docs/guide/links.md index 8b000f0..45a6a99 100644 --- a/docs/guide/links.md +++ b/docs/guide/links.md @@ -23,7 +23,7 @@ import { Link } from '@inertiajs/react' Home ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' @@ -34,7 +34,7 @@ import { inertia, Link } from '@inertiajs/svelte' ``` > [!TIP] -> The `use:inertia` directive can be applied to any HTML element. +> The `use:inertia` action can be applied to any HTML element. ::: @@ -46,10 +46,10 @@ By default, Inertia renders links as anchor `` elements. However, you can cha ```vue import { Link } from '@inertiajs/vue3' -Logout +Logout // Renders as... - +// ``` == React @@ -57,30 +57,31 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' -Logout +export default () => ( + Logout +) // Renders as... - +// ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte -import { inertia } from '@inertiajs/svelte' + - +Logout // Renders as... - +// ``` -> [!NOTE] -> Svelte does not support dynamic elements yet, but you can use the `inertia` directive to achieve the same results. - ::: -> [!WARNING] -> Creating `POST/PUT/PATCH/DELETE` anchor `` links is discouraged as it causes "Open Link in New Tab / Window" accessibility issues. Instead, consider using a more appropriate element, such as a ` + + +Logout ``` ::: @@ -143,12 +146,12 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' - + Save ``` @@ -178,14 +181,14 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' - + -Save +Save ``` ::: @@ -213,12 +216,12 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' -Home +Home Home ``` @@ -245,21 +248,21 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - + Search ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' - + - + -Search +Search ``` ::: @@ -287,12 +290,12 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' -Home +Home Home ``` @@ -324,12 +327,12 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' -Show active +Show active Show active ``` @@ -390,16 +393,16 @@ const { url, component } = usePage() Users ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte -import { page } from '@inertiajs/svelte' +import { inertia, Link, page } from '@inertiajs/svelte' // URL exact match... -Users +Users // Component exact match... -Users +Users // URL starts with (/users, /users/create, /users/1, etc.)... Users diff --git a/docs/guide/load-when-visible.md b/docs/guide/load-when-visible.md index ca4c605..b00125f 100644 --- a/docs/guide/load-when-visible.md +++ b/docs/guide/load-when-visible.md @@ -36,21 +36,45 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 ```svelte
Loading...
- {permissions} + + {#each permissions as permission} + + {/each}
``` + +== Svelte 5 + +```svelte + + + + {#snippet fallback()} +
Loading...
+ {/snippet} + + {#each permissions as permission} + + {/each} +
+``` + ::: If you'd like to load multiple props when an element becomes visible, you can provide an array to the `data` prop. @@ -85,19 +109,39 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 ```svelte
Loading...
+ + +
+``` + +== Svelte 5 + +```svelte + + + + {#snippet fallback()} +
Loading...
+ {/snippet} +
``` @@ -120,6 +164,7 @@ import { WhenVisible } from '@inertiajs/vue3' +
@@ -131,6 +176,7 @@ import { WhenVisible } from '@inertiajs/vue3' ```jsx import { WhenVisible } from '@inertiajs/react' + export default () => ( Loading...}> @@ -138,22 +184,44 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 ```svelte
Loading...
- {permissions} + + {#each permissions as permission} + + {/each} +
+ +== Svelte 5 + +```svelte + + + + {#snippet fallback()} +
Loading...
+ {/snippet} + + {#each permissions as permission} + + {/each}
``` -::: In the above example, the data will start loading 500 pixels before the element is visible. @@ -186,16 +254,31 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 + +```svelte + + + + // ... + +``` + +== Svelte 5 ```svelte - {products} + ``` ::: @@ -235,16 +318,31 @@ export default () => ( ) ``` -== Svelte +== Svelte 4 ```svelte + + + + +``` + +== Svelte 5 + +```svelte + - {products} + ``` ::: diff --git a/docs/guide/manual-visits.md b/docs/guide/manual-visits.md index 8c95d06..29f4053 100644 --- a/docs/guide/manual-visits.md +++ b/docs/guide/manual-visits.md @@ -75,7 +75,7 @@ router.visit(url, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -142,7 +142,7 @@ router.delete(url, options) router.reload(options) // Uses the current URL ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -180,7 +180,7 @@ import { router } from '@inertiajs/react' router.visit(url, { method: 'post' }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -226,7 +226,7 @@ router.visit('/users', { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -267,7 +267,7 @@ router.post('/users', { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js @@ -310,7 +310,7 @@ router.post('/users', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -352,7 +352,7 @@ router.post('/companies', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -387,7 +387,7 @@ import { router } from '@inertiajs/react' router.get('/users', { search: 'John' }, { replace: true }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -428,7 +428,7 @@ import { router } from '@inertiajs/react' router.get('/users', { search: 'John' }, { preserveState: true }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -459,7 +459,7 @@ import { router } from '@inertiajs/react' router.get('/users', { search: 'John' }, { preserveState: 'errors' }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -492,7 +492,7 @@ router.post('/users', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -527,7 +527,7 @@ import { router } from '@inertiajs/react' router.visit(url, { preserveScroll: false }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -556,7 +556,7 @@ import { router } from '@inertiajs/react' router.visit(url, { preserveScroll: 'errors' }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -589,7 +589,7 @@ router.post('/users', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -624,7 +624,7 @@ import { router } from '@inertiajs/react' router.visit('/users', { search: 'John' }, { only: ['users'] }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -667,7 +667,7 @@ router.post('/users', data, { this.cancelToken.cancel() ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -721,7 +721,7 @@ router.post('/users', data, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -762,7 +762,7 @@ router.delete(`/users/${user.id}`, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -809,7 +809,7 @@ router.post(url, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' diff --git a/docs/guide/merging-props.md b/docs/guide/merging-props.md index 3c9cfb9..694e3a7 100644 --- a/docs/guide/merging-props.md +++ b/docs/guide/merging-props.md @@ -59,7 +59,7 @@ import { router } from '@inertiajs/react' router.reload({ reset: ['results'] }) ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { router } from '@inertiajs/svelte' diff --git a/docs/guide/pages.md b/docs/guide/pages.md index eb1fb71..8cf95bb 100644 --- a/docs/guide/pages.md +++ b/docs/guide/pages.md @@ -45,7 +45,7 @@ export default function Welcome({ user }) { } ``` -== Svelte +== Svelte 4 ```svelte + + Welcome + + - - Welcome - -

Welcome

+

Welcome

Hello {user.name}, welcome to your first Inertia app!

``` +== Svelte 5 + +```svelte + + + + Welcome + + + +

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

+
+``` ::: Given the page above, you can render the page by returning an Inertia response from a controller or route. In this example, let's assume this page is stored at `app/frontend/pages/User/Show.(jsx|vue|svelte)` within a Rails application. @@ -124,7 +143,7 @@ export default function Layout({ children }) { } ``` -== Svelte +== Svelte 4 ```svelte + +
+
+ Home + About + Contact +
+
+ {@render children()} +
+
+``` + ::: As you can see, there is nothing Inertia specific within this template. This is just a typical component. @@ -174,7 +214,7 @@ defineProps({ user: Object }) ``` @@ -187,7 +227,7 @@ import Layout from '../Layout' const Home = ({ user }) => { return ( <> -

Welcome

+

Welcome

Hello {user.name}, welcome to your first Inertia app!

) @@ -198,7 +238,7 @@ Home.layout = (page) => export default Home ``` -== Svelte +== Svelte 4 ```svelte -

Welcome

+

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

+``` + +== Svelte 5 + +```svelte + + + + +

Welcome

Hello {user.name}, welcome to your first Inertia app!

``` @@ -241,7 +296,7 @@ defineProps({ user: Object }) ``` @@ -266,7 +321,7 @@ import NestedLayout from './NestedLayout' const Home = ({ user }) => { return ( <> -

Welcome

+

Welcome

Hello {user.name}, welcome to your first Inertia app!

) @@ -281,12 +336,19 @@ Home.layout = (page) => ( export default Home ``` -== Svelte +== Svelte 4 ```svelte @@ -294,7 +356,29 @@ export default Home export let user -

Welcome

+

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

+``` + +== Svelte 5 + +```svelte + + + + +

Welcome

Hello {user.name}, welcome to your first Inertia app!

``` @@ -340,7 +424,7 @@ createInertiaApp({ }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js // frontend/entrypoints/inertia.js @@ -399,7 +483,7 @@ createInertiaApp({ }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js // frontend/entrypoints/inertia.js @@ -413,7 +497,6 @@ createInertiaApp({ default: page.default, layout: name.startsWith('Public/') ? undefined : Layout, } - return page }, // ... }) diff --git a/docs/guide/partial-reloads.md b/docs/guide/partial-reloads.md index c4b8ac3..209964c 100644 --- a/docs/guide/partial-reloads.md +++ b/docs/guide/partial-reloads.md @@ -32,7 +32,7 @@ router.visit(url, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -67,7 +67,7 @@ router.visit(url, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { router } from '@inertiajs/svelte' @@ -102,7 +102,7 @@ import { router } from '@inertiajs/react' router.reload({ only: ['users'] }) ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { router } from '@inertiajs/svelte' @@ -135,12 +135,12 @@ import { Link } from '@inertiajs/react' ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte import { inertia, Link } from '@inertiajs/svelte' -Show active +Show active Show active ``` diff --git a/docs/guide/polling.md b/docs/guide/polling.md index d087ae2..1c111f4 100644 --- a/docs/guide/polling.md +++ b/docs/guide/polling.md @@ -21,7 +21,7 @@ import { usePoll } from '@inertiajs/react' usePoll(2000) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { usePoll } from '@inertiajs/svelte' @@ -63,7 +63,7 @@ usePoll(2000, { }) ``` -== Svelte +== Svelte 4|Svelte 5 ```js import { usePoll } from '@inertiajs/svelte' @@ -117,7 +117,7 @@ export default () => { } ``` -== Svelte +== Svelte 4|Svelte 5 ```svelte -Home + ``` == React @@ -20,13 +24,15 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' -Home +export default () => Home ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + Home @@ -44,12 +50,15 @@ By default, Inertia renders links as anchor `` elements. However, you can cha == Vue ```vue + -Logout - -// Renders as... -// + ``` == React @@ -58,7 +67,9 @@ import { Link } from '@inertiajs/vue3' import { Link } from '@inertiajs/react' export default () => ( - Logout + + Logout + ) // Renders as... @@ -74,8 +85,8 @@ export default () => ( Logout -// Renders as... -// + + ``` ::: @@ -91,9 +102,13 @@ You can specify the HTTP request method for an Inertia link request using the `m == Vue ```vue + -Logout + ``` == React @@ -101,15 +116,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Logout - +export default () => ( + + Logout + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + @@ -126,14 +145,15 @@ When making `POST` or `PUT` requests, you may wish to add additional data to the == Vue ```vue + -Save + ``` == React @@ -141,17 +161,26 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Save - +export default () => ( + + Save + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + - + Save ``` @@ -166,9 +195,13 @@ The `headers` prop allows you to add custom headers to an Inertia link. However, == Vue ```vue + -Save + ``` == React @@ -176,15 +209,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Save - +export default () => ( + + Save + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + @@ -201,9 +238,13 @@ The `replace` prop allows you to specify the browser's history behavior. By defa == Vue ```vue + -Home + ``` == React @@ -211,15 +252,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Home - +export default () => ( + + Home + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + Home @@ -236,11 +281,15 @@ You can preserve a page component's local state using the `preserveState` prop. == Vue ```vue + - + ``` == React @@ -248,19 +297,29 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - +export default () => ( + <> + -Search + + Search + + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + - + Search ``` @@ -275,9 +334,13 @@ You can use the `preserveScroll` prop to prevent Inertia from automatically rese == Vue ```vue + -Home + ``` == React @@ -285,15 +348,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Home - +export default () => ( + + Home + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + Home @@ -312,9 +379,13 @@ The `only` prop allows you to specify that only a subset of a page's props (data == Vue ```vue + -Show active + ``` == React @@ -322,15 +393,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Show active - +export default () => ( + + Show active + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + Show active @@ -349,28 +424,29 @@ It's often desirable to set an active state for navigation links based on the cu == Vue ```vue + -// URL exact match... -Users - -// Component exact match... -Users - -// URL starts with (/users, /users/create, /users/1, etc.)... -Users - -// Component starts with (Users/Index, Users/Create, Users/Show, etc.)... -Users + ``` == React @@ -378,37 +454,67 @@ import { Link } from '@inertiajs/vue3' ```jsx import { usePage } from '@inertiajs/react' -const { url, component } = usePage() - -// URL exact match... -Users - -// Component exact match... -Users - -// URL starts with (/users, /users/create, /users/1, etc.)... -Users - -// Component starts with (Users/Index, Users/Create, Users/Show, etc.)... -Users +export default () => { + const { url, component } = usePage() + + return ( + <> + // URL exact match... + + Users + + // Component exact match... + + Users + + // URL starts with (/users, /users/create, /users/1, etc.)... + + Users + + // Component starts with (Users/Index, Users/Create, Users/Show, etc.)... + + Users + + + ) +} ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link, page } from '@inertiajs/svelte' - -// URL exact match... -Users - -// Component exact match... -Users - -// URL starts with (/users, /users/create, /users/1, etc.)... -Users + -// Component starts with (Users/Index, Users/Create, Users/Show, etc.)... -Users + ``` ::: diff --git a/docs/guide/load-when-visible.md b/docs/guide/load-when-visible.md index 493adaa..a2752e9 100644 --- a/docs/guide/load-when-visible.md +++ b/docs/guide/load-when-visible.md @@ -141,10 +141,11 @@ export default () => ( {#snippet fallback()}
Loading...
{/snippet} - +
``` + ::: ## Loading before visible @@ -197,7 +198,7 @@ export default () => (
Loading...
- + {#each permissions as permission} {/each} @@ -267,7 +268,7 @@ export default () => ( - // ... + ``` @@ -284,6 +285,7 @@ export default () => (
``` + ::: ## Always trigger @@ -336,7 +338,7 @@ export default () => ( ``` == Svelte 5 - + ```svelte

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

``` @@ -265,6 +267,7 @@ export default Home

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

``` @@ -357,6 +360,7 @@ export default Home

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

``` @@ -379,6 +383,7 @@ export default Home

Welcome

+

Hello {user.name}, welcome to your first Inertia app!

``` diff --git a/docs/guide/partial-reloads.md b/docs/guide/partial-reloads.md index f7a6102..871e769 100644 --- a/docs/guide/partial-reloads.md +++ b/docs/guide/partial-reloads.md @@ -88,7 +88,7 @@ Since partial reloads can only be made to the same page component the user is al :::tabs key:frameworks == Vue -```vue +```js import { router } from '@inertiajs/vue3' router.reload({ only: ['users'] }) @@ -96,7 +96,7 @@ router.reload({ only: ['users'] }) == React -```jsx +```js import { router } from '@inertiajs/react' router.reload({ only: ['users'] }) @@ -104,7 +104,7 @@ router.reload({ only: ['users'] }) == Svelte 4|Svelte 5 -```svelte +```js import { router } from '@inertiajs/svelte' router.reload({ only: ['users'] }) @@ -120,9 +120,13 @@ It's also possible to perform partial reloads with Inertia links using the `only == Vue ```vue + -Show active + ``` == React @@ -130,15 +134,19 @@ import { Link } from '@inertiajs/vue3' ```jsx import { Link } from '@inertiajs/react' - - Show active - +export default () => ( + + Show active + +) ``` == Svelte 4|Svelte 5 ```svelte -import { inertia, Link } from '@inertiajs/svelte' + Show active diff --git a/docs/guide/polling.md b/docs/guide/polling.md index 1c111f4..ec035ae 100644 --- a/docs/guide/polling.md +++ b/docs/guide/polling.md @@ -27,11 +27,11 @@ usePoll(2000) import { usePoll } from '@inertiajs/svelte' usePoll(2000) ``` + ::: If you need to pass additional request options to the poll helper, you can pass any of the `router.reload` options as the second parameter. - :::tabs key:frameworks == Vue @@ -40,11 +40,11 @@ import { usePoll } from '@inertiajs/vue3' usePoll(2000, { onStart() { - console.log('Polling request started') + console.log('Polling request started') }, onFinish() { - console.log('Polling request finished') - } + console.log('Polling request finished') + }, }) ``` @@ -55,11 +55,11 @@ import { usePoll } from '@inertiajs/react' usePoll(2000, { onStart() { - console.log('Polling request started') + console.log('Polling request started') }, onFinish() { - console.log('Polling request finished') - } + console.log('Polling request finished') + }, }) ``` @@ -70,16 +70,17 @@ import { usePoll } from '@inertiajs/svelte' usePoll(2000, { onStart() { - console.log('Polling request started') + console.log('Polling request started') }, onFinish() { - console.log('Polling request finished') - } + console.log('Polling request finished') + }, }) ``` + ::: -If you'd like more control over the polling behavior, the poll helper provides `stop` and `start` methods that allow you to manually start and stop polling. You can pass the `autoStart: false` option to the poll helper to prevent it from automatically starting polling when the component is mounted. +If you'd like more control over the polling behavior, the poll helper provides `stop` and `start` methods that allow you to manually start and stop polling. You can pass the `autoStart: false` option to the poll helper to prevent it from automatically starting polling when the component is mounted. :::tabs key:frameworks == Vue @@ -87,16 +88,19 @@ If you'd like more control over the polling behavior, the poll helper provides ` ```vue - ``` == React @@ -105,9 +109,13 @@ const { start, stop } = usePoll(2000, {}, { import { usePoll } from '@inertiajs/react' export default () => { - const { start, stop } = usePoll(2000, {}, { - autoStart: false, - }) + const { start, stop } = usePoll( + 2000, + {}, + { + autoStart: false, + }, + ) return (
@@ -121,18 +129,22 @@ export default () => { ```svelte ``` -::: +::: ## Throttling @@ -144,9 +156,13 @@ By default, the poll helper will throttle requests by 90% when the browser tab i ```js import { usePoll } from '@inertiajs/vue3' -usePoll(2000, {}, { - keepAlive: true, -}) +usePoll( + 2000, + {}, + { + keepAlive: true, + }, +) ``` == React @@ -154,9 +170,13 @@ usePoll(2000, {}, { ```js import { usePoll } from '@inertiajs/react' -usePoll(2000, {}, { - keepAlive: true, -}) +usePoll( + 2000, + {}, + { + keepAlive: true, + }, +) ``` == Svelte 4|Svelte 5 @@ -164,8 +184,13 @@ usePoll(2000, {}, { ```js import { usePoll } from '@inertiajs/svelte' -usePoll(2000, {}, { - keepAlive: true, -}) +usePoll( + 2000, + {}, + { + keepAlive: true, + }, +) ``` + ::: diff --git a/docs/guide/prefetching.md b/docs/guide/prefetching.md index 82e34db..0a227e6 100644 --- a/docs/guide/prefetching.md +++ b/docs/guide/prefetching.md @@ -11,7 +11,7 @@ To prefetch data for a page, you can use the `prefetch` method on the Inertia li ```vue