Skip to content

Commit 22e470e

Browse files
Update to Svelte 5
1 parent e682200 commit 22e470e

24 files changed

+843
-424
lines changed

package-lock.json

+596-282
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,23 @@
2222
"@sveltejs/adapter-auto": "^3.3.1",
2323
"@sveltejs/adapter-node": "^5.2.9",
2424
"@sveltejs/kit": "^2.7.3",
25-
"@sveltejs/vite-plugin-svelte": "^3.1.2",
25+
"@sveltejs/vite-plugin-svelte": "^4.0.0",
2626
"@testing-library/svelte": "^5.2.4",
2727
"@testing-library/user-event": "^14.5.2",
2828
"@types/eslint": "^9.6.1",
2929
"eslint": "^9.13.0",
3030
"eslint-config-prettier": "^9.1.0",
3131
"eslint-plugin-svelte": "^2.46.0",
3232
"globals": "^15.11.0",
33-
"happy-dom": "^15.7.4",
33+
"jsdom": "^25.0.1",
3434
"prettier": "^3.3.3",
3535
"prettier-plugin-svelte": "^3.2.7",
36-
"sass": "^1.80.4",
37-
"svelte": "^4.2.19",
36+
"sass": "^1.80.5",
37+
"svelte": "^5.1.4",
3838
"svelte-check": "^4.0.5",
3939
"tslib": "^2.8.0",
4040
"typescript": "^5.6.3",
41-
"typescript-eslint": "^8.11.0",
41+
"typescript-eslint": "^8.12.2",
4242
"vite": "^5.4.10",
4343
"vitest": "^2.1.4"
4444
},

src/lib/components/avatar.svelte

+8-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
import { t } from 'i18next';
33
import type { User } from '$lib/openapi/generated';
44
5-
export let user: User | null = null;
6-
export let size: number;
7-
let tint: string;
5+
interface Props {
6+
user?: User | null;
7+
size: number;
8+
}
89
9-
$: tint = user != null ? `rgb(${user.tint.r}, ${user.tint.g}, ${user.tint.b})` : '#7f7f7f3f';
10+
let { user = null, size }: Props = $props();
11+
let tint: string = $derived(
12+
user != null ? `rgb(${user.tint.r}, ${user.tint.g}, ${user.tint.b})` : '#7f7f7f3f'
13+
);
1014
</script>
1115

1216
{#if user?.avatar}

src/lib/components/event-listener.svelte

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
import { browser } from '$app/environment';
44
import { eventBus, type Listener, type Class } from '$lib/events';
55
6-
export let type: Class<T>;
7-
export let listener: Listener<T>;
6+
interface Props {
7+
type: Class<T>;
8+
listener: Listener<T>;
9+
}
10+
11+
let { type, listener }: Props = $props();
812
913
if (browser) {
1014
onMount(() => eventBus.addListener(type, listener));

src/lib/components/icon.svelte

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<script lang="ts">
2-
export let size = '24px';
2+
import type { Snippet } from 'svelte';
3+
4+
interface Props {
5+
size?: string;
6+
children: Snippet;
7+
}
8+
9+
let { size = '24px', children }: Props = $props();
310
</script>
411

512
<svg width={size} height={size} viewBox="0 0 240 240" class="icon">
6-
<slot />
13+
{@render children()}
714
</svg>
815

916
<style lang="scss">

src/lib/components/inputs/button.svelte

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
<script lang="ts">
2+
import type { Snippet } from 'svelte';
23
import Loader from './button/loader.svelte';
34
4-
export let type: HTMLButtonElement['type'];
5-
export let primary = false;
6-
export let disabled = false;
7-
export let loading = false;
5+
interface Props {
6+
type: HTMLButtonElement['type'];
7+
primary?: boolean;
8+
disabled?: boolean;
9+
loading?: boolean;
10+
children?: Snippet;
11+
onClick: (event: MouseEvent) => void;
12+
}
13+
14+
let {
15+
type,
16+
primary = false,
17+
disabled = false,
18+
loading = false,
19+
children,
20+
onClick
21+
}: Props = $props();
22+
23+
function onClickPreventingDefault(event: MouseEvent) {
24+
event.preventDefault();
25+
onClick(event);
26+
}
827
</script>
928

10-
<button {type} disabled={disabled || loading} class:primary on:click|preventDefault>
11-
<span class:invisible={loading}><slot /></span>
29+
<button {type} disabled={disabled || loading} class:primary onclick={onClickPreventingDefault}>
30+
<span class:invisible={loading}>{@render children?.()}</span>
1231
{#if loading}
1332
<span class="loader"><Loader /></span>
1433
{/if}

src/lib/components/inputs/image-picker.svelte

+18-15
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,51 @@
11
<script lang="ts">
2-
import { createEventDispatcher } from 'svelte';
2+
import type { Snippet } from 'svelte';
33
4-
export let title: string;
4+
interface Props {
5+
title: string;
6+
children: Snippet;
7+
onFile: (file: File) => void;
8+
}
9+
10+
let { title, children, onFile }: Props = $props();
511
6-
const dispatch = createEventDispatcher();
7-
let input: HTMLInputElement;
12+
let input: HTMLInputElement | undefined = $state();
813
914
function onInput() {
10-
const file = input.files?.item(0);
15+
const file = input?.files?.item(0);
1116
1217
if (file) {
13-
dispatch('file', file);
18+
onFile(file);
1419
}
1520
}
1621
1722
function onDragOver(event: DragEvent) {
23+
event.preventDefault();
24+
1825
if (event.dataTransfer) {
1926
event.dataTransfer.dropEffect = 'copy';
2027
}
2128
}
2229
2330
function onDrop(event: DragEvent) {
31+
event.preventDefault();
2432
const file = event.dataTransfer?.files.item(0);
2533
2634
if (file) {
27-
dispatch('file', file);
35+
onFile(file);
2836
}
2937
}
3038
</script>
3139

32-
<label
33-
{title}
34-
class="image-picker"
35-
on:dragover|preventDefault={onDragOver}
36-
on:drop|preventDefault={onDrop}
37-
>
40+
<label {title} class="image-picker" ondragover={onDragOver} ondrop={onDrop}>
3841
<input
3942
type="file"
4043
accept="image/jpeg,image/png,image/wepb"
4144
class="input"
42-
on:input={onInput}
45+
oninput={onInput}
4346
bind:this={input}
4447
/>
45-
<slot />
48+
{@render children()}
4649
</label>
4750

4851
<style lang="scss">

src/lib/components/inputs/text-area.svelte

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
<script lang="ts">
2-
export let label: string;
3-
export let name: string;
4-
export let placeholder: string;
5-
export let maxLength: number;
6-
export let value = '';
7-
export let disabled = false;
2+
interface Props {
3+
label: string;
4+
name: string;
5+
placeholder: string;
6+
maxLength: number;
7+
value?: string;
8+
disabled?: boolean;
9+
}
10+
11+
let {
12+
label,
13+
name,
14+
placeholder,
15+
maxLength,
16+
value = $bindable(''),
17+
disabled = false
18+
}: Props = $props();
819
</script>
920

1021
<label class="text-area">
1122
<span>{label}</span>
12-
<textarea contenteditable {name} {placeholder} {disabled} maxlength={maxLength} bind:value />
23+
<textarea contenteditable {name} {placeholder} {disabled} maxlength={maxLength} bind:value
24+
></textarea>
1325
</label>
1426

1527
<style lang="scss">

src/lib/components/inputs/text-field.svelte

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
<script lang="ts">
22
import { onMount } from 'svelte';
33
4-
export let label: string;
5-
export let name: string;
6-
export let placeholder: string;
7-
export let value = '';
8-
export let autofocus = false;
9-
export let disabled = false;
4+
interface Props {
5+
label: string;
6+
name: string;
7+
placeholder: string;
8+
value?: string;
9+
autofocus?: boolean;
10+
disabled?: boolean;
11+
}
12+
13+
let {
14+
label,
15+
name,
16+
placeholder,
17+
value = $bindable(''),
18+
autofocus = false,
19+
disabled = false
20+
}: Props = $props();
1021
11-
let input: HTMLInputElement;
22+
let input: HTMLInputElement | undefined = $state();
1223
1324
if (autofocus) {
1425
onMount(() =>
1526
setTimeout(() => {
1627
if (!value) {
17-
input.focus();
28+
input?.focus();
1829
}
1930
})
2031
);

src/lib/components/list.svelte

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
<script lang="ts">
2-
export let borderless = false;
2+
import type { Snippet } from 'svelte';
3+
4+
interface Props {
5+
borderless?: boolean;
6+
header?: Snippet;
7+
body?: Snippet;
8+
}
9+
10+
let { borderless = false, header, body }: Props = $props();
311
</script>
412

513
<table class="list" class:borderless>
614
<thead>
7-
<slot name="header" />
15+
{@render header?.()}
816
</thead>
917
<tbody>
10-
<slot name="body" />
18+
{@render body?.()}
1119
</tbody>
1220
</table>
1321

1422
<style lang="scss">
15-
@import '$lib/style/mixins';
23+
@use '$lib/style/mixins';
1624
1725
@mixin borders {
1826
:global(tr:first-child td) {
@@ -37,7 +45,7 @@
3745
border-radius: 1em;
3846
border-spacing: 0;
3947
40-
@include expanded-width {
48+
@include mixins.expanded-width {
4149
width: unset;
4250
min-width: 600px;
4351
}
@@ -53,7 +61,7 @@
5361
&.borderless thead :global(td) {
5462
border-bottom: 1px solid var(--color-border);
5563
56-
@include expanded-width {
64+
@include mixins.expanded-width {
5765
border-bottom: unset;
5866
}
5967
}
@@ -63,7 +71,7 @@
6371
}
6472
6573
tbody {
66-
@include expanded-width {
74+
@include mixins.expanded-width {
6775
@include borders;
6876
}
6977

src/lib/components/saved-value.svelte

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
import { StorageChange } from '$lib/events';
66
import EventListener from './event-listener.svelte';
77
8-
export let name: N;
9-
export let store: Writable<T | null>;
8+
interface Props {
9+
name: N;
10+
store: Writable<T | null>;
11+
}
12+
13+
let { name, store }: Props = $props();
1014
1115
onMount(() => {
1216
$store = getStoredItem<T>(name) ?? $store;
@@ -30,5 +34,5 @@
3034
}
3135
</script>
3236

33-
<svelte:window on:storage={onExternalStorageEvent} />
37+
<svelte:window onstorage={onExternalStorageEvent} />
3438
<EventListener type={StorageChange} listener={(e) => onInternalStorageChange(e.detail)} />

src/lib/openapi/fakes/users-endpoint.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ export default class FakeUsersEndpointApi implements UsersEndpointApiInterface {
8989
body: Blob,
9090
initOverrides?: RequestInit | InitOverrideFunction
9191
): Promise<string> {
92-
switch (await body.text()) {
93-
case await FakeUsersEndpointApi.normalImageFile.text():
92+
switch (body) {
93+
case FakeUsersEndpointApi.normalImageFile:
9494
return FakeUsersEndpointApi.normalImageFile.name;
95-
case await FakeUsersEndpointApi.largeImageFile.text():
95+
case FakeUsersEndpointApi.largeImageFile:
9696
fail(413);
9797
default:
9898
fail(415);

0 commit comments

Comments
 (0)