@@ -27,6 +27,11 @@ const props = defineProps({
27
27
type: Number ,
28
28
required: true ,
29
29
},
30
+ progressStep: {
31
+ type: Number ,
32
+ required: false ,
33
+ default: 10 ,
34
+ },
30
35
duration: {
31
36
type: Number ,
32
37
required: false ,
@@ -80,15 +85,24 @@ const progressRef = ref<InstanceType<typeof NProgress>>();
80
85
const containerRef = computed (() => container ?.value ?? progressRef .value ?.$el );
81
86
82
87
const editing = ref (false );
83
- const angleProgress = ref (0 );
88
+ const angleProgress = ref (_progress .value );
89
+
90
+ const emitProgress = computed (() => {
91
+ if (! transform ?.value || typeof transform .value !== ' function' ) {
92
+ return angleProgress .value ;
93
+ }
94
+ return transform .value (angleProgress .value );
95
+ });
96
+
97
+ const dirtyProgress = computed (() => emitProgress .value !== _progress .value );
84
98
85
99
const debounceEmitProgress = debounce (
86
100
() => emit (' onEditProgress' , angleProgress .value ),
87
101
500 ,
88
102
);
89
103
90
104
const editProgress = computed (() => {
91
- if (! editing .value ) return _progress .value ;
105
+ if (! dirtyProgress .value ) return _progress .value ;
92
106
debounceEmitProgress ();
93
107
return angleProgress .value ;
94
108
});
@@ -104,17 +118,14 @@ const color = computed(() => {
104
118
return ' color-primary' ;
105
119
});
106
120
107
- const emitProgress = computed (() => {
108
- if (! transform ?.value || typeof transform .value !== ' function' ) {
109
- return angleProgress .value ;
110
- }
111
- return transform .value (angleProgress .value );
112
- });
113
-
114
- const isMouse = (event : MouseEvent | TouchEvent ): event is MouseEvent =>
115
- event .type === ' mousemove' || event .type === ' mousedown' || event .type === ' mouseup' ;
121
+ const isMouse = (event : MouseEvent | TouchEvent | PointerEvent ): event is MouseEvent =>
122
+ event .type === ' mousemove' ||
123
+ event .type === ' mousedown' ||
124
+ event .type === ' mouseup' ||
125
+ event .type === ' click' ;
116
126
117
127
const listener = (event : MouseEvent | TouchEvent ) => {
128
+ if (! editing .value ) return ;
118
129
if (! progressRef .value ?.$el ) return ;
119
130
// Get the bounding rectangle of the tracking box
120
131
const rect = progressRef .value ?.$el .getBoundingClientRect ();
@@ -134,13 +145,44 @@ const listener = (event: MouseEvent | TouchEvent) => {
134
145
angleProgress .value = Math .round (degrees / 3.6 );
135
146
};
136
147
137
- const onClick = (event : MouseEvent | TouchEvent ) => {
148
+ const onProgress = (value : number ) => {
149
+ if (! editable .value ) return ;
150
+ if (editing .value ) return ;
151
+ angleProgress .value = value < 0 ? 0 : value ;
152
+ };
153
+
154
+ const onEdit = (value : number = emitProgress .value ) => {
155
+ if (value === _progress .value ) return ;
156
+ emit (' onEdit' , value );
157
+ };
158
+
159
+ const onEnter = (event : KeyboardEvent ) => {
160
+ if (! editable .value ) return ;
161
+ if (editing .value ) {
162
+ editing .value = ! editing .value ;
163
+ return emit (' onEditing' , editing .value );
164
+ }
165
+ if (emitProgress .value === _progress .value ) {
166
+ editing .value = ! editing .value ;
167
+ emit (' onEditing' , editing .value );
168
+ return progressRef .value ?.$el ?.focus ();
169
+ }
170
+ return onEdit ();
171
+ };
172
+
173
+ const onClick = async (event : MouseEvent | TouchEvent ) => {
138
174
if (! editable .value ) return ;
139
175
editing .value = ! editing .value ;
140
176
emit (' onEditing' , editing .value );
141
- if (! editing .value ) return emit ( ' onEdit' , emitProgress . value );
177
+ if (! editing .value ) return onEdit ( );
142
178
progressRef .value ?.$el ?.focus ();
143
- listener (event );
179
+ setTimeout (() => listener (event ), 100 );
180
+ };
181
+
182
+ const onBlur = () => {
183
+ editing .value = false ;
184
+ emit (' onEditing' , editing .value );
185
+ angleProgress .value = _progress .value ;
144
186
};
145
187
146
188
onMounted (async () => {
@@ -149,6 +191,7 @@ onMounted(async () => {
149
191
async val => {
150
192
await wait (delay .value );
151
193
_progress .value = val ;
194
+ if (! editing .value ) angleProgress .value = val ;
152
195
},
153
196
{ immediate: true },
154
197
);
@@ -188,15 +231,18 @@ onBeforeUnmount(() => {
188
231
type =" circle"
189
232
:percentage =" editProgress"
190
233
:style =" {
191
- '--duration': `${ progressDuration }ms`,
192
- '--custom-progress-color': `var(--${ color })`,
234
+ '--duration': `${progressDuration}ms`,
235
+ '--custom-progress-color': `var(--${color})`,
193
236
}"
194
237
:tabindex =" editable ? 0 : undefined"
195
238
@click =" onClick"
196
- @keydown.enter =" onClick"
239
+ @keydown.enter =" onEnter"
240
+ @keydown.up.prevent =" onProgress(emitProgress + progressStep)"
241
+ @keydown.down.prevent =" onProgress(emitProgress - progressStep)"
242
+ @keydown.esc =" onBlur"
197
243
@touchstart =" onClick"
198
244
@touchend =" onClick"
199
- @blur =" editing = false "
245
+ @blur =" onBlur "
200
246
>
201
247
<span v-if =" editing" >{{ emitProgress }}</span >
202
248
<AnimatedNumber
@@ -227,10 +273,6 @@ onBeforeUnmount(() => {
227
273
228
274
.custom-color {
229
275
--n-fill-color : var (--custom-progress-color , var (--color-info )) !important ;
230
-
231
- & :focus-visible {
232
- outline : -webkit-focus-ring-color auto 1px ;
233
- }
234
276
}
235
277
236
278
.spin {
@@ -245,6 +287,13 @@ onBeforeUnmount(() => {
245
287
246
288
.progress {
247
289
width : var (--progress-size );
290
+ border : 2px solid transparent ;
291
+ border-radius : 50% ;
292
+ outline : none ;
293
+
294
+ & :focus-visible {
295
+ border : 2px solid var (--custom-progress-color , var (--color-info ));
296
+ }
248
297
249
298
:deep (path.n-progress-graph-circle-fill ) {
250
299
transition :
0 commit comments