Skip to content

Commit 73a293f

Browse files
pedroborgesreinink
andauthored
Improve Svelte use:inertia and <Link /> (#1344)
* Simplify options merge logic * Stop dispatching click event * Dispatch Inertia events on the HTML node With this they can be listened the Svelte way on HTML elements. ```svelte <a use:inertia={{ method: 'post' }} href="/toggle" on:success={({ detail }) => alert('Success!')}>Toggle</a> ``` * Add "as" prop and remove duplicated logic * Forward all Inertia events * Add default preserveState value * Add Svelte Prettier plugin Co-authored-by: Jonathan Reinink <jonathan@reinink.ca>
1 parent c033e72 commit 73a293f

File tree

5 files changed

+84
-67
lines changed

5 files changed

+84
-67
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"packages/*"
55
],
66
"dependencies": {
7-
"prettier": "^2.7.1"
7+
"prettier": "^2.7.1",
8+
"prettier-plugin-svelte": "^2.8.1"
89
}
910
}

packages/svelte/src/App.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
store.update((current) => ({
1313
component,
1414
page,
15-
key: preserveState ? current.key : Date.now()
15+
key: preserveState ? current.key : Date.now(),
1616
}))
17-
}
17+
},
1818
})
1919
2020
$: child = $store.component && h($store.component.default, $store.page.props)

packages/svelte/src/Link.svelte

+51-41
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,59 @@
11
<script>
2-
import { mergeDataIntoQueryString, router, shouldIntercept } from '@inertiajs/core'
3-
import { beforeUpdate, createEventDispatcher } from 'svelte'
4-
5-
const dispatch = createEventDispatcher()
6-
7-
export let
8-
data = {},
9-
href,
10-
method = 'get',
11-
replace = false,
12-
preserveScroll = false,
13-
preserveState = null,
14-
only = [],
15-
headers = {}
2+
import { beforeUpdate } from 'svelte'
3+
import { default as inertia } from './link'
4+
5+
export let href
6+
export let as = 'a'
7+
export let data = {}
8+
export let method = 'get'
9+
export let replace = false
10+
export let preserveScroll = false
11+
export let preserveState = null
12+
export let only = []
13+
export let headers = {}
14+
export let queryStringArrayFormat = 'brackets'
1615
1716
beforeUpdate(() => {
18-
method = method.toLowerCase()
19-
const [_href, _data] = mergeDataIntoQueryString(method, href, data)
20-
href = _href
21-
data = _data
22-
23-
if (method !== 'get') {
24-
console.warn(`Creating POST/PUT/PATCH/DELETE <a> links is discouraged as it causes "Open Link in New Tab/Window" accessibility issues.\n\nPlease specify a more appropriate element using the "inertia" directive. For example:\n\n<button use:inertia={{ method: 'post', href: '${href}' }}>...</button>`)
17+
if (as === 'a' && method.toLowerCase() !== 'get') {
18+
console.warn(
19+
`Creating POST/PUT/PATCH/DELETE <a> links is discouraged as it causes "Open Link in New Tab/Window" accessibility issues.\n\nPlease specify a more appropriate element using the "as" attribute. For example:\n\n<Link href="${href}" method="${method}" as="button">...</Link>`,
20+
)
2521
}
2622
})
27-
28-
function visit(event) {
29-
dispatch('click', event)
30-
31-
if (shouldIntercept(event)) {
32-
event.preventDefault()
33-
34-
router.visit(href, {
35-
data,
36-
method,
37-
preserveScroll,
38-
preserveState: preserveState !== null ? preserveState : (method !== 'get'),
39-
replace,
40-
only,
41-
headers,
42-
})
43-
}
44-
}
4523
</script>
4624

47-
<a {...$$restProps} {href} on:click={visit}>
25+
<svelte:element
26+
this={as}
27+
use:inertia={{
28+
...(as !== 'a' ? { href } : {}),
29+
data,
30+
method,
31+
replace,
32+
preserveScroll,
33+
preserveState: preserveState ?? method !== 'get',
34+
only,
35+
headers,
36+
queryStringArrayFormat,
37+
}}
38+
{...as === 'a' ? { href } : {}}
39+
{...$$restProps}
40+
on:focus
41+
on:blur
42+
on:click
43+
on:dblclick
44+
on:mousedown
45+
on:mousemove
46+
on:mouseout
47+
on:mouseover
48+
on:mouseup
49+
on:cancel-token
50+
on:before
51+
on:start
52+
on:progress
53+
on:finish
54+
on:cancel
55+
on:success
56+
on:error
57+
>
4858
<slot />
49-
</a>
59+
</svelte:element>

packages/svelte/src/Render.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
return {
44
component,
55
...(props ? { props } : {}),
6-
...(children ? { children } : {})
6+
...(children ? { children } : {}),
77
}
88
}
99
</script>

packages/svelte/src/link.js

+28-22
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,52 @@
11
import { mergeDataIntoQueryString, router, shouldIntercept } from '@inertiajs/core'
2-
import { createEventDispatcher } from 'svelte'
32

43
export default (node, options = {}) => {
5-
const [href, data] = mergeDataIntoQueryString(
6-
options.method || 'get',
7-
node.href || options.href || '',
8-
options.data || {},
9-
options.queryStringArrayFormat || 'brackets',
10-
)
4+
const [href, data] = hrefAndData(options)
115
node.href = href
126
options.data = data
137

14-
const dispatch = createEventDispatcher()
15-
16-
function visit(event) {
17-
dispatch('click', event)
8+
function fireEvent(name, eventOptions = {}) {
9+
return node.dispatchEvent(new CustomEvent(name, eventOptions))
10+
}
1811

19-
const href = node.href || options.href
12+
function hrefAndData(options) {
13+
return mergeDataIntoQueryString(
14+
options.method || 'get',
15+
node.href || options.href || '',
16+
options.data || {},
17+
options.queryStringArrayFormat || 'brackets',
18+
)
19+
}
2020

21-
if (!href) {
21+
function visit(event) {
22+
if (!node.href) {
2223
throw new Error('Option "href" is required')
2324
}
2425

2526
if (shouldIntercept(event)) {
2627
event.preventDefault()
27-
router.visit(href, options)
28+
29+
router.visit(node.href, {
30+
onCancelToken: () => fireEvent('cancel-token'),
31+
onBefore: (visit) => fireEvent('before', { detail: { visit } }),
32+
onStart: (visit) => fireEvent('start', { detail: { visit } }),
33+
onProgress: (progress) => fireEvent('progress', { detail: { progress } }),
34+
onFinish: (visit) => fireEvent('finish', { detail: { visit } }),
35+
onCancel: () => fireEvent('cancel'),
36+
onSuccess: (page) => fireEvent('success', { detail: { page } }),
37+
onError: (errors) => fireEvent('error', { detail: { errors } }),
38+
...options,
39+
})
2840
}
2941
}
3042

3143
node.addEventListener('click', visit)
3244

3345
return {
3446
update(newOptions) {
35-
const [href, data] = mergeDataIntoQueryString(
36-
newOptions.method || 'get',
37-
node.href || newOptions.href,
38-
newOptions.data || {},
39-
newOptions.queryStringArrayFormat || 'brackets',
40-
)
47+
const [href, data] = hrefAndData(newOptions)
4148
node.href = href
42-
newOptions.data = data
43-
options = newOptions
49+
options = { ...newOptions, data }
4450
},
4551
destroy() {
4652
node.removeEventListener('click', visit)

0 commit comments

Comments
 (0)