Skip to content

Commit

Permalink
[Svelte] Upgrade to Svelte 5. Drop Svelte 4 support.
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesst20 committed Jan 8, 2025
1 parent 0766df1 commit 5f99318
Show file tree
Hide file tree
Showing 39 changed files with 1,372 additions and 816 deletions.
1,664 changes: 1,100 additions & 564 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"react": "^16.9.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"dependencies": {
"@jamesst20/inertia-core": "2.0.0",
"@jamesst20/inertia-core": "file:../core",
"lodash.isequal": "^4.5.0"
}
}
10 changes: 5 additions & 5 deletions packages/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,27 @@
"!dist/**/*.spec.*"
],
"peerDependencies": {
"svelte": "^4.0.0 || ^5.0.0 || ^5.0.0-next.244"
"svelte": "^5.0.0"
},
"dependencies": {
"@jamesst20/inertia-core": "2.0.0",
"@jamesst20/inertia-core": "file:../core",
"html-escape": "^2.0.0",
"lodash": "^4.5.0"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.2.0",
"@sveltejs/kit": "^2.5.26",
"@sveltejs/package": "^2.3.4",
"@sveltejs/vite-plugin-svelte": "^3.1.2",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@types/html-escape": "^2.0.2",
"@types/lodash": "^4.17.7",
"axios": "^1.7.6",
"publint": "^0.2.10",
"svelte": "^4.2.16",
"svelte": "^5.16.2",
"svelte-check": "^4.0.0",
"tslib": "^2.7.0",
"typescript": "^5.5.4",
"vite": "^5.4.8"
"vite": "^6.0.0"
},
"svelte": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down
12 changes: 5 additions & 7 deletions packages/svelte/src/components/App.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script context="module" lang="ts">
<script module lang="ts">
import type { ComponentResolver, ResolvedComponent } from '../types'
import { type Page } from '@jamesst20/inertia-core'
import type { Page } from '@jamesst20/inertia-core'
export interface InertiaAppProps {
initialComponent: ResolvedComponent
Expand All @@ -13,16 +13,14 @@
import type { LayoutType, LayoutResolver } from '../types'
import { router, type PageProps } from '@jamesst20/inertia-core'
import Render, { h, type RenderProps } from './Render.svelte'
import { setPage } from '../page'
import { setPage } from '../page.svelte'
export let initialComponent: InertiaAppProps['initialComponent']
export let initialPage: InertiaAppProps['initialPage']
export let resolveComponent: InertiaAppProps['resolveComponent']
let { initialComponent, initialPage, resolveComponent }: InertiaAppProps = $props()
let component = initialComponent
let key: number | null = null
let page = initialPage
let renderProps = resolveRenderProps(component, page, key)
let renderProps = $state(resolveRenderProps(component, page, key))
setPage(page)
Expand Down
33 changes: 19 additions & 14 deletions packages/svelte/src/components/Deferred.svelte
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
<script module lang="ts">
import type { Snippet } from 'svelte'
type DeferedProps = {
data: string | string[]
children: Snippet
fallback: Snippet
}
</script>
<script lang="ts">
import { page } from '../index'
import { onDestroy } from 'svelte'
export let data: string | string[]
let { data, children, fallback }: DeferedProps = $props()
let currentPage = $derived(page.current)
let keys = $derived(Array.isArray(data) ? data : [data])
let loaded = $state(false)
const keys = Array.isArray(data) ? data : [data]
let loaded = false
const unsubscribe = page.subscribe(({ props }) => {
$effect(() => {
// Ensures the slot isn't loaded before the deferred props are available
window.queueMicrotask(() => {
loaded = keys.every((key) => typeof props[key] !== 'undefined')
loaded = keys.every((key) => typeof currentPage?.props?.[key] !== 'undefined')
})
})
onDestroy(() => {
unsubscribe()
})
if (!$$slots.fallback) {
if (!fallback) {
throw new Error('`<Deferred>` requires a `<svelte:fragment slot="fallback">` slot')
}
</script>

{#if loaded}
<slot />
{@render children?.()}
{:else}
<slot name="fallback" />
{@render fallback?.()}
{/if}
82 changes: 38 additions & 44 deletions packages/svelte/src/components/Link.svelte
Original file line number Diff line number Diff line change
@@ -1,37 +1,48 @@
<script module lang="ts">
import type { Snippet } from 'svelte'
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'
import type { ActionParameters } from '../link'
type LinkProps = {
href: string
as?: keyof HTMLElementTagNameMap,
class?: string
children: Snippet
} & Partial<ActionParameters> & Partial<HTMLAnchorAttributes> & Partial<HTMLButtonAttributes>
</script>
<script lang="ts">
import type {
CacheForOption,
FormDataConvertible,
LinkPrefetchOption,
Method,
PreserveStateOption,
} from '@jamesst20/inertia-core'
import { inertia } from '../index'
export let href: string
export let as: keyof HTMLElementTagNameMap = 'a'
export let data: Record<string, FormDataConvertible> = {}
export let method: Method = 'get'
export let replace: boolean = false
export let preserveScroll: PreserveStateOption = false
export let preserveState: PreserveStateOption | null = null
export let only: string[] = []
export let except: string[] = []
export let headers: Record<string, string> = {}
export let queryStringArrayFormat: 'brackets' | 'indices' = 'brackets'
export let async: boolean = false
export let prefetch: boolean | LinkPrefetchOption | LinkPrefetchOption[] = false
export let cacheFor: CacheForOption | CacheForOption[] = 0
let {
href,
as = 'a',
data = {},
method = 'get',
replace = false,
preserveScroll = false,
preserveState = undefined,
only = [],
except = [],
headers = {},
queryStringArrayFormat = 'brackets',
async = false,
prefetch = false,
cacheFor = 0,
children,
...restProps
}: LinkProps = $props()
$: asProp = method !== 'get' ? 'button' : as.toLowerCase()
$: elProps =
let asProp = $derived(method !== 'get' ? 'button' : as.toLowerCase())
let elProps = $derived(
{
a: { href },
button: { type: 'button' },
}[asProp] || {}
}[asProp] || {})
</script>

<!-- svelte-ignore a11y-no-static-element-interactions -->

<!-- svelte-ignore a11y_no_static_element_interactions -->
<svelte:element
this={asProp}
use:inertia={{
Expand All @@ -49,25 +60,8 @@
prefetch,
cacheFor,
}}
{...$$restProps}
{...elProps}
on:focus
on:blur
on:click
on:dblclick
on:mousedown
on:mousemove
on:mouseout
on:mouseover
on:mouseup
on:cancel-token
on:before
on:start
on:progress
on:finish
on:cancel
on:success
on:error
{...restProps as any}
>
<slot />
{@render children()}
</svelte:element>
42 changes: 25 additions & 17 deletions packages/svelte/src/components/Render.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
<script context="module" lang="ts">
<script module lang="ts">
import type { PageProps } from '@jamesst20/inertia-core'
import type { ComponentType } from 'svelte'
type RenderComponentProps = {
component: ComponentType
props?: PageProps
childComponents?: RenderProps[]
key?: number | null
}
export type RenderProps = {
component: ComponentType
props?: PageProps
children?: RenderProps[]
childComponents?: RenderProps[]
key?: number | null
}
export type RenderFunction = {
(component: ComponentType, props?: PageProps, children?: RenderProps[], key?: number | null): RenderProps
(component: ComponentType, children?: RenderProps[], key?: number | null): RenderProps
(component: ComponentType, props?: PageProps, childComponents?: RenderProps[], key?: number | null): RenderProps
(component: ComponentType, childComponents?: RenderProps[], key?: number | null): RenderProps
}
export const h: RenderFunction = (component, propsOrChildren, childrenOrKey, key: number | null = null) => {
Expand All @@ -21,7 +28,7 @@
component,
key: hasProps ? key : typeof childrenOrKey === 'number' ? childrenOrKey : null,
props: hasProps ? propsOrChildren : {},
children: hasProps
childComponents: hasProps
? ((Array.isArray(childrenOrKey)
? childrenOrKey
: childrenOrKey !== null
Expand All @@ -37,26 +44,27 @@
</script>

<script lang="ts">
export let component: ComponentType
export let props: PageProps = {}
export let children: RenderProps[] = []
export let key: number | null = null
import Render from './Render.svelte'
let { component, props = {}, childComponents = [], key = null }: RenderComponentProps = $props()
let DynamicComponent = $derived(component)
</script>

{#if component}
{#if DynamicComponent}
<!--
Add the `key` only to the last (page) component in the tree.
This ensures that the page component re-renders when `preserveState` is disabled,
while the layout components are persisted across page changes. -->
{#key children?.length === 0 ? key : null}
{#if children.length > 0}
<svelte:component this={component} {...props}>
{#each children as child}
<svelte:self {...child} />
{#key childComponents?.length === 0 ? key : null}
{#if childComponents.length > 0}
<DynamicComponent {...props}>
{#each childComponents as child}
<Render {...child} />
{/each}
</svelte:component>
</DynamicComponent>
{:else}
<svelte:component this={component} {...props} />
<DynamicComponent {...props} />
{/if}
{/key}
{/if}
58 changes: 37 additions & 21 deletions packages/svelte/src/components/WhenVisible.svelte
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
<script module lang="ts">
import type { Snippet } from 'svelte'
type WhenVisibleProps = {
data: string | string[]
params?: ReloadOptions
buffer?: number
as?: keyof HTMLElementTagNameMap
always?: boolean
children: Snippet
fallback: Snippet
}
</script>
<script lang="ts">
import { router, type ReloadOptions } from '@jamesst20/inertia-core'
import { onDestroy, onMount } from 'svelte'
export let data: string | string[] = ''
export let params: ReloadOptions = {}
export let buffer: number = 0
export let as: keyof HTMLElementTagNameMap = 'div'
export let always: boolean = false
let loaded = false
let fetching = false
let el: HTMLElement
let observer: IntersectionObserver | null = null
onMount(() => {
let {
data = '',
params = {},
buffer = 0,
as = 'div',
always = false,
children,
fallback
}: WhenVisibleProps = $props()
let loaded = $state(false)
let fetching = $state(false)
let el = $state<HTMLElement>()
$effect(() => {
if (!el) {
return
}
observer = new IntersectionObserver(
const observer = new IntersectionObserver(
(entries) => {
if (!entries[0].isIntersecting) {
return
Expand Down Expand Up @@ -55,10 +71,10 @@
)
observer.observe(el)
})
onDestroy(() => {
observer?.disconnect()
return () => {
observer?.disconnect()
}
})
function getReloadParams(): Partial<ReloadOptions> {
Expand All @@ -81,7 +97,7 @@
{/if}

{#if loaded}
<slot />
{:else if $$slots.fallback}
<slot name="fallback" />
{/if}
{@render children?.()}
{:else}
{@render fallback?.()}
{/if}
2 changes: 1 addition & 1 deletion packages/svelte/src/createInertiaApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default async function createInertiaApp({
const svelteApp = setup({
el,
App: App as unknown as AppComponent,
props
props,
})

if (isServer) {
Expand Down
Loading

0 comments on commit 5f99318

Please sign in to comment.