Skip to content

Commit 617ffc4

Browse files
fix(repl): ComponentSelector (#495)
* Push * (fix) various issues about tab renaming (#497) * Add changeset --------- Co-authored-by: Paolo Ricciuti <[email protected]>
1 parent 40763e2 commit 617ffc4

File tree

6 files changed

+151
-111
lines changed

6 files changed

+151
-111
lines changed

.changeset/bright-shoes-boil.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/repl': patch
3+
---
4+
5+
Fix ComponentSelector

packages/repl/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"build": "vite build && npm run package",
4040
"preview": "vite preview",
4141
"package": "svelte-kit sync && svelte-package && publint",
42-
"watch": "svelte-package --watch",
42+
"package:watch": "svelte-package --watch",
4343
"prepublishOnly": "npm run package",
4444
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
4545
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch"

packages/repl/src/lib/Input/ComponentSelector.svelte

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
export let show_modified;
88
99
/** @type {ReturnType<typeof createEventDispatcher<{
10-
* remove: { files: import('$lib/types').File[] },
11-
* add: { files: import('$lib/types').File[] },
10+
* remove: { files: import('$lib/types').File[]; diff: import('$lib/types').File },
11+
* add: { files: import('$lib/types').File[]; diff: import('$lib/types').File },
1212
* }>>} */
1313
const dispatch = createEventDispatcher();
1414
@@ -18,33 +18,39 @@
1818
module_editor,
1919
rebundle,
2020
selected,
21-
selected_index,
21+
selected_name,
2222
EDITOR_STATE_MAP
2323
} = get_repl_context();
2424
25-
/** @type {number} */
26-
let editing_index = -1;
25+
/** @type {string | null} */
26+
let editing_name = null;
27+
28+
let input_value = '';
2729
28-
/** @param {number} index */
29-
function select_file(index) {
30-
if ($selected_index !== index) {
31-
editing_index = -1;
32-
handle_select(index);
30+
/** @param {string} filename */
31+
function select_file(filename) {
32+
if ($selected_name !== filename) {
33+
editing_name = null;
34+
handle_select(filename);
3335
}
3436
}
3537
36-
/** @param {number} index */
37-
function edit_tab(index) {
38-
if ($selected_index === index) {
39-
editing_index = $selected_index;
38+
/** @param {import('$lib/types').File} file */
39+
function edit_tab(file) {
40+
if ($selected_name === get_full_filename(file)) {
41+
editing_name = get_full_filename(file);
42+
input_value = file.name;
4043
}
4144
}
4245
4346
async function close_edit() {
44-
const match = /(.+)\.(svelte|js|json|md|css)$/.exec($selected?.name ?? '');
47+
const match = /(.+)\.(svelte|js|json|md|css)$/.exec(input_value ?? '');
48+
49+
const edited_file = $files.find((val) => get_full_filename(val) === editing_name);
4550
46-
const edited_file = $files[editing_index];
47-
edited_file.name = match ? match[1] : edited_file.name;
51+
if (!edited_file) return;
52+
53+
edited_file.name = match ? match[1] : input_value;
4854
4955
if (!$selected) return;
5056
@@ -53,20 +59,43 @@
5359
let name = $selected.name;
5460
5561
do {
56-
$files[$selected_index].name = `${name}_${i++}`;
62+
const file = $files.find(
63+
(val) =>
64+
get_full_filename(val) === get_full_filename(edited_file) &&
65+
// @ts-ignore
66+
val.source === $selected.source
67+
);
68+
69+
if (!file) break;
70+
71+
file.name = `${name}_${i++}`;
5772
} while (is_file_name_used($selected));
5873
59-
$files[$selected_index] = edited_file;
74+
const idx = $files.findIndex(
75+
(val) => get_full_filename(val) === get_full_filename(edited_file)
76+
);
77+
$files[idx] = edited_file;
6078
}
6179
62-
if (match?.[2]) $files[$selected_index].type = match[2];
63-
64-
editing_index = -1;
80+
const idx = $files.findIndex(
81+
(val) => get_full_filename(val) === get_full_filename(edited_file)
82+
);
83+
if (match?.[2]) $files[idx].type = match[2];
84+
85+
if (editing_name) {
86+
const old_state = EDITOR_STATE_MAP.get(editing_name);
87+
if (old_state) {
88+
EDITOR_STATE_MAP.set(get_full_filename(edited_file), old_state);
89+
EDITOR_STATE_MAP.delete(editing_name);
90+
}
91+
}
6592
66-
EDITOR_STATE_MAP.delete(get_full_filename($selected));
93+
editing_name = null;
6794
6895
// re-select, in case the type changed
69-
handle_select($selected_index);
96+
handle_select(get_full_filename(edited_file));
97+
98+
$files = $files;
7099
71100
// focus the editor, but wait a beat (so key events aren't misdirected)
72101
await tick();
@@ -77,25 +106,24 @@
77106
}
78107
79108
/**
80-
* @param {number} index
109+
* @param {string} filename
81110
*/
82-
function remove(index) {
83-
let result = confirm(
84-
`Are you sure you want to delete ${$files[index].name}.${$files[index].type}?`
85-
);
111+
function remove(filename) {
112+
const file = $files.find((val) => get_full_filename(val) === filename);
113+
const idx = $files.findIndex((val) => get_full_filename(val) === filename);
114+
115+
if (!file) return;
116+
117+
let result = confirm(`Are you sure you want to delete ${get_full_filename(file)}?`);
86118
87119
if (!result) return;
88120
89-
if (index !== -1) {
90-
$files = $files.filter((_, idx) => idx !== index);
121+
$files = $files.filter((file) => get_full_filename(file) !== filename);
91122
92-
dispatch('remove', { files: $files });
93-
} else {
94-
console.error(`Could not find component! That's... odd`);
95-
}
123+
dispatch('remove', { files: $files, diff: file });
96124
97-
EDITOR_STATE_MAP.delete(get_full_filename($files[index]));
98-
handle_select(($selected_index = index - 1));
125+
EDITOR_STATE_MAP.delete(get_full_filename(file));
126+
handle_select(($selected_name = idx === 1 ? 'App.svelte' : get_full_filename(file)));
99127
}
100128
101129
/** @param {FocusEvent & { currentTarget: HTMLInputElement }} event */
@@ -117,11 +145,17 @@
117145
118146
$files = $files.concat(file);
119147
120-
editing_index = $files.length - 1;
148+
editing_name = get_full_filename(file);
149+
150+
input_value = file.name;
151+
152+
handle_select(editing_name);
121153
122-
handle_select(editing_index);
154+
rebundle();
155+
156+
dispatch('add', { files: $files, diff: file });
123157
124-
dispatch('add', { files: $files });
158+
$files = $files;
125159
}
126160
127161
/** @param {import('$lib/types').File} editing */
@@ -171,61 +205,64 @@
171205
<div class="component-selector">
172206
{#if $files.length}
173207
<div class="file-tabs" on:dblclick={add_new}>
174-
{#each $files as file, index (file)}
208+
{#each $files as file, index (file.name)}
209+
{@const filename = get_full_filename(file)}
175210
<div
176211
id={file.name}
177212
class="button"
178213
role="button"
179214
tabindex="0"
180-
class:active={index === $selected_index}
181-
class:draggable={index !== editing_index && index !== 0}
215+
class:active={filename === $selected_name}
216+
class:draggable={filename !== editing_name && index !== 0}
182217
class:drag-over={over === file.name}
183-
on:click={() => select_file(index)}
184-
on:keyup={(e) => e.key === ' ' && select_file(index)}
218+
on:click={() => select_file(filename)}
219+
on:keyup={(e) => e.key === ' ' && select_file(filename)}
185220
on:dblclick|stopPropagation={() => {}}
186-
draggable={index !== editing_index}
221+
draggable={filename !== editing_name}
187222
on:dragstart={dragStart}
188223
on:dragover|preventDefault={dragOver}
189224
on:dragleave={dragLeave}
190225
on:drop|preventDefault={dragEnd}
191226
>
192227
<i class="drag-handle" />
193-
{#if file.name === 'App' && index !== editing_index}
228+
{#if file.name === 'App' && filename !== editing_name}
194229
<div class="uneditable">
195230
App.svelte{#if show_modified && file.modified}*{/if}
196231
</div>
197-
{:else if index === editing_index}
198-
{@const file = $files[editing_index]}
199-
200-
<span class="input-sizer">
201-
{file.name + (/\./.test(file.name) ? '' : `.${file.type}`)}
202-
</span>
203-
204-
<!-- svelte-ignore a11y-autofocus -->
205-
<input
206-
autofocus
207-
spellcheck={false}
208-
bind:value={$files[editing_index].name}
209-
on:focus={select_input}
210-
on:blur={close_edit}
211-
on:keydown={(e) =>
212-
e.key === 'Enter' && !is_file_name_used(file) && e.currentTarget.blur()}
213-
class:duplicate={is_file_name_used(file)}
214-
/>
232+
{:else if filename === editing_name}
233+
{@const editing_file = $files.find((file) => get_full_filename(file) === editing_name)}
234+
235+
{#if editing_file}
236+
<span class="input-sizer">
237+
{input_value + (/\./.test(input_value) ? '' : `.${editing_file.type}`)}
238+
</span>
239+
240+
<!-- svelte-ignore a11y-autofocus -->
241+
<input
242+
autofocus
243+
spellcheck={false}
244+
bind:value={input_value}
245+
on:focus={select_input}
246+
on:blur={close_edit}
247+
on:keydown={(e) =>
248+
e.key === 'Enter' && !is_file_name_used(editing_file) && e.currentTarget.blur()}
249+
class:duplicate={is_file_name_used(editing_file)}
250+
/>
251+
{/if}
215252
{:else}
216253
<div
217254
class="editable"
218255
title="edit component name"
219-
on:click={() => edit_tab(index)}
220-
on:keyup={(e) => e.key === ' ' && edit_tab(index)}
256+
on:click={() => edit_tab(file)}
257+
on:keyup={(e) => e.key === ' ' && edit_tab(file)}
221258
>
222259
{file.name}.{file.type}{#if show_modified && file.modified}*{/if}
223260
</div>
224261
225262
<span
226263
class="remove"
227-
on:click={() => remove(index)}
228-
on:keyup={(e) => e.key === ' ' && remove(index)}
264+
on:click={() => remove(filename)}
265+
on:keyup={(e) => e.key === ' ' && remove(filename)}
229266
>
230267
<svg width="12" height="12" viewBox="0 0 24 24">
231268
<line stroke="#999" x1="18" y1="6" x2="6" y2="18" />

0 commit comments

Comments
 (0)