@@ -4,7 +4,7 @@ import { computed, inject, ref, VNode, Ref } from 'vue'
44
55const store = inject (' store' ) as Store
66
7- const pending = ref (false )
7+ const pending = ref < boolean | string > (false )
88const pendingFilename = ref (' Comp.vue' )
99const importMapFile = ' import-map.json'
1010const showImportMap = inject (' import-map' ) as Ref <boolean >
@@ -36,17 +36,18 @@ function startAddFile() {
3636 pending .value = true
3737}
3838
39- function cancelAddFile () {
39+ function cancelNameFile () {
4040 pending .value = false
4141}
4242
4343function focus({ el }: VNode ) {
4444 ;(el as HTMLInputElement ).focus ()
4545}
4646
47- function doneAddFile () {
47+ function doneNameFile () {
4848 if (! pending .value ) return
4949 const filename = pendingFilename .value
50+ const oldFilename = pending .value === true ? ' ' : pending .value
5051
5152 if (! / \. (vue| js| ts| css| json)$ / .test (filename )) {
5253 store .state .errors = [
@@ -55,14 +56,28 @@ function doneAddFile() {
5556 return
5657 }
5758
58- if (filename in store .state .files ) {
59+ if (filename !== oldFilename && filename in store .state .files ) {
5960 store .state .errors = [` File "${filename }" already exists. ` ]
6061 return
6162 }
6263
6364 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
6681}
6782
6883const fileSel = ref (null )
@@ -85,32 +100,35 @@ function horizontalScroll(e: WheelEvent) {
85100 @wheel =" horizontalScroll"
86101 ref =" fileSel"
87102 >
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 >
114132 <button class =" add" @click =" startAddFile" >+</button >
115133
116134 <div v-if =" showImportMap" class =" import-map-wrapper" >
0 commit comments