@@ -4,7 +4,7 @@ import { computed, inject, ref, VNode, Ref } from 'vue'
4
4
5
5
const store = inject (' store' ) as Store
6
6
7
- const pending = ref (false )
7
+ const pending = ref < boolean | string > (false )
8
8
const pendingFilename = ref (' Comp.vue' )
9
9
const importMapFile = ' import-map.json'
10
10
const showImportMap = inject (' import-map' ) as Ref <boolean >
@@ -36,17 +36,18 @@ function startAddFile() {
36
36
pending .value = true
37
37
}
38
38
39
- function cancelAddFile () {
39
+ function cancelNameFile () {
40
40
pending .value = false
41
41
}
42
42
43
43
function focus({ el }: VNode ) {
44
44
;(el as HTMLInputElement ).focus ()
45
45
}
46
46
47
- function doneAddFile () {
47
+ function doneNameFile () {
48
48
if (! pending .value ) return
49
49
const filename = pendingFilename .value
50
+ const oldFilename = pending .value === true ? ' ' : pending .value
50
51
51
52
if (! / \. (vue| js| ts| css| json)$ / .test (filename )) {
52
53
store .state .errors = [
@@ -55,14 +56,28 @@ function doneAddFile() {
55
56
return
56
57
}
57
58
58
- if (filename in store .state .files ) {
59
+ if (filename !== oldFilename && filename in store .state .files ) {
59
60
store .state .errors = [` File "${filename }" already exists. ` ]
60
61
return
61
62
}
62
63
63
64
store .state .errors = []
64
- cancelAddFile ()
65
- store .addFile (filename )
65
+ cancelNameFile ()
66
+
67
+ if (filename === oldFilename ) {
68
+ return
69
+ }
70
+
71
+ if (oldFilename ) {
72
+ store .renameFile (oldFilename , filename )
73
+ } else {
74
+ store .addFile (filename )
75
+ }
76
+ }
77
+
78
+ function editFileName(file : string ) {
79
+ pendingFilename .value = file
80
+ pending .value = file
66
81
}
67
82
68
83
const fileSel = ref (null )
@@ -85,32 +100,35 @@ function horizontalScroll(e: WheelEvent) {
85
100
@wheel =" horizontalScroll"
86
101
ref =" fileSel"
87
102
>
88
- <div
89
- v-for =" (file, i) in files"
90
- class =" file"
91
- :class =" { active: store.state.activeFile.filename === file }"
92
- @click =" store.setActive(file)"
93
- >
94
- <span class =" label" >{{
95
- file === importMapFile ? 'Import Map' : file
96
- }}</span >
97
- <span v-if =" i > 0" class =" remove" @click.stop =" store.deleteFile(file)" >
98
- <svg class =" icon" width =" 12" height =" 12" viewBox =" 0 0 24 24" >
99
- <line stroke =" #999" x1 =" 18" y1 =" 6" x2 =" 6" y2 =" 18" ></line >
100
- <line stroke =" #999" x1 =" 6" y1 =" 6" x2 =" 18" y2 =" 18" ></line >
101
- </svg >
102
- </span >
103
- </div >
104
- <div v-if =" pending" class =" file pending" >
105
- <input
106
- v-model =" pendingFilename"
107
- spellcheck =" false"
108
- @blur =" doneAddFile"
109
- @keyup.enter =" doneAddFile"
110
- @keyup.esc =" cancelAddFile"
111
- @vue:mounted =" focus"
112
- />
113
- </div >
103
+ <template v-for =" (file , i ) in files " >
104
+ <div
105
+ v-if =" pending !== file"
106
+ class =" file"
107
+ :class =" { active: store.state.activeFile.filename === file }"
108
+ @click =" store.setActive(file)"
109
+ @dblclick =" i > 0 && editFileName(file)"
110
+ >
111
+ <span class =" label" >{{
112
+ file === importMapFile ? 'Import Map' : file
113
+ }}</span >
114
+ <span v-if =" i > 0" class =" remove" @click.stop =" store.deleteFile(file)" >
115
+ <svg class =" icon" width =" 12" height =" 12" viewBox =" 0 0 24 24" >
116
+ <line stroke =" #999" x1 =" 18" y1 =" 6" x2 =" 6" y2 =" 18" ></line >
117
+ <line stroke =" #999" x1 =" 6" y1 =" 6" x2 =" 18" y2 =" 18" ></line >
118
+ </svg >
119
+ </span >
120
+ </div >
121
+ <div v-if =" (pending === true && i === files.length - 1) || (pending === file)" class =" file pending" >
122
+ <input
123
+ v-model =" pendingFilename"
124
+ spellcheck =" false"
125
+ @blur =" doneNameFile"
126
+ @keyup.enter =" doneNameFile"
127
+ @keyup.esc =" cancelNameFile"
128
+ @vue:mounted =" focus"
129
+ />
130
+ </div >
131
+ </template >
114
132
<button class =" add" @click =" startAddFile" >+</button >
115
133
116
134
<div v-if =" showImportMap" class =" import-map-wrapper" >
0 commit comments