Skip to content

Commit bd3b7d3

Browse files
authored
Migrate Editor.svelte to Svelte 5 plus TypeScript (#413)
* migrate editor * typescript
1 parent 3e2f01b commit bd3b7d3

File tree

1 file changed

+51
-45
lines changed

1 file changed

+51
-45
lines changed

apps/svelte.dev/src/routes/tutorial/[...slug]/Editor.svelte

Lines changed: 51 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script>
1+
<script lang="ts">
22
import { browser } from '$app/environment';
33
import { afterNavigate, beforeNavigate } from '$app/navigation';
44
import { acceptCompletion } from '@codemirror/autocomplete';
@@ -18,24 +18,25 @@
1818
import { files, selected_file, selected_name, update_file } from './state.js';
1919
import { toStore } from 'svelte/store';
2020
import { autocomplete_for_svelte } from '@sveltejs/site-kit/codemirror';
21+
import type { Diagnostic } from '@codemirror/lint';
22+
import type { Exercise, Stub } from '$lib/tutorial';
2123
22-
/** @type {import('$lib/tutorial').Exercise}*/
23-
export let exercise;
24+
interface Props {
25+
exercise: Exercise;
26+
}
27+
28+
let { exercise }: Props = $props();
2429
25-
/** @type {HTMLDivElement} */
26-
let container;
30+
let container = $state() as HTMLDivElement;
2731
28-
let preserve_editor_focus = false;
32+
let preserve_editor_focus = $state(false);
2933
let skip_reset = true;
3034
31-
/** @type {any} */
32-
let remove_focus_timeout;
35+
let remove_focus_timeout = $state<any>();
3336
34-
/** @type {Map<string, import('@codemirror/state').EditorState>} */
35-
let editor_states = new Map();
37+
let editor_states = new Map<string, EditorState>();
3638
37-
/** @type {import('@codemirror/view').EditorView} */
38-
let editor_view;
39+
let editor_view = $state() as EditorView;
3940
4041
const warnings = toStore(() => adapter_state.warnings);
4142
@@ -47,34 +48,10 @@
4748
svelteTheme
4849
];
4950
50-
$: reset($files);
51-
52-
$: select_state($selected_name);
53-
54-
$: if (editor_view) {
55-
if ($selected_name) {
56-
const current_warnings = $warnings[$selected_name] || [];
57-
const diagnostics = current_warnings.map((warning) => {
58-
/** @type {import('@codemirror/lint').Diagnostic} */
59-
const diagnostic = {
60-
from: warning.start.character,
61-
to: warning.end.character,
62-
severity: 'warning',
63-
message: warning.message
64-
};
65-
66-
return diagnostic;
67-
});
68-
const transaction = setDiagnostics(editor_view.state, diagnostics);
69-
70-
editor_view.dispatch(transaction);
71-
}
72-
}
73-
7451
let installed_vim = false;
7552
7653
/** @param {import('$lib/tutorial').Stub[]} $files */
77-
async function reset($files) {
54+
async function reset($files: Stub[]) {
7855
if (skip_reset) return;
7956
8057
let should_install_vim = localStorage.getItem('vim') === 'true';
@@ -126,7 +103,7 @@
126103
lang = [
127104
svelte(),
128105
...autocomplete_for_svelte(
129-
() => /** @type {import('$lib/tutorial').FileStub} */ ($selected_file).name,
106+
() => $selected_file!.name,
130107
() =>
131108
$files
132109
.filter(
@@ -152,8 +129,7 @@
152129
}
153130
}
154131
155-
/** @param {string | null} $selected_name */
156-
function select_state($selected_name) {
132+
function select_state($selected_name: string | null) {
157133
if (skip_reset) return;
158134
159135
const state =
@@ -210,15 +186,45 @@
210186
select_state($selected_name);
211187
}
212188
});
189+
190+
$effect(() => {
191+
reset($files);
192+
});
193+
194+
$effect(() => {
195+
select_state($selected_name);
196+
});
197+
198+
$effect(() => {
199+
if (editor_view) {
200+
if ($selected_name) {
201+
const current_warnings = $warnings[$selected_name] || [];
202+
const diagnostics = current_warnings.map((warning) => {
203+
/** @type {import('@codemirror/lint').Diagnostic} */
204+
const diagnostic: Diagnostic = {
205+
from: warning.start.character,
206+
to: warning.end.character,
207+
severity: 'warning',
208+
message: warning.message
209+
};
210+
211+
return diagnostic;
212+
});
213+
const transaction = setDiagnostics(editor_view.state, diagnostics);
214+
215+
editor_view.dispatch(transaction);
216+
}
217+
}
218+
});
213219
</script>
214220

215221
<svelte:window
216-
on:pointerdown={(e) => {
217-
if (!container.contains(/** @type {HTMLElement} */ (e.target))) {
222+
onpointerdown={(e) => {
223+
if (!container.contains((e.target as HTMLElement))) {
218224
preserve_editor_focus = false;
219225
}
220226
}}
221-
on:message={(e) => {
227+
onmessage={(e) => {
222228
if (preserve_editor_focus && e.data.type === 'iframe_took_focus') {
223229
editor_view.focus();
224230
}
@@ -228,11 +234,11 @@
228234
<div
229235
class="container"
230236
bind:this={container}
231-
on:focusin={() => {
237+
onfocusin={() => {
232238
clearTimeout(remove_focus_timeout);
233239
preserve_editor_focus = true;
234240
}}
235-
on:focusout={() => {
241+
onfocusout={() => {
236242
// Heuristic: user did refocus themmselves if iframe_took_focus
237243
// doesn't happen in the next few miliseconds. Needed
238244
// because else navigations inside the iframe refocus the editor.

0 commit comments

Comments
 (0)