Skip to content

Commit 06e1c7a

Browse files
committed
fix(progress): fix error on click and rework keyboard inputs
1 parent 1c28d52 commit 06e1c7a

File tree

1 file changed

+71
-22
lines changed

1 file changed

+71
-22
lines changed

src/components/common/numbers/ProgressNumber.vue

+71-22
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ const props = defineProps({
2727
type: Number,
2828
required: true,
2929
},
30+
progressStep: {
31+
type: Number,
32+
required: false,
33+
default: 10,
34+
},
3035
duration: {
3136
type: Number,
3237
required: false,
@@ -80,15 +85,24 @@ const progressRef = ref<InstanceType<typeof NProgress>>();
8085
const containerRef = computed(() => container?.value ?? progressRef.value?.$el);
8186
8287
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);
8498
8599
const debounceEmitProgress = debounce(
86100
() => emit('onEditProgress', angleProgress.value),
87101
500,
88102
);
89103
90104
const editProgress = computed(() => {
91-
if (!editing.value) return _progress.value;
105+
if (!dirtyProgress.value) return _progress.value;
92106
debounceEmitProgress();
93107
return angleProgress.value;
94108
});
@@ -104,17 +118,14 @@ const color = computed(() => {
104118
return 'color-primary';
105119
});
106120
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';
116126
117127
const listener = (event: MouseEvent | TouchEvent) => {
128+
if (!editing.value) return;
118129
if (!progressRef.value?.$el) return;
119130
// Get the bounding rectangle of the tracking box
120131
const rect = progressRef.value?.$el.getBoundingClientRect();
@@ -134,13 +145,44 @@ const listener = (event: MouseEvent | TouchEvent) => {
134145
angleProgress.value = Math.round(degrees / 3.6);
135146
};
136147
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) => {
138174
if (!editable.value) return;
139175
editing.value = !editing.value;
140176
emit('onEditing', editing.value);
141-
if (!editing.value) return emit('onEdit', emitProgress.value);
177+
if (!editing.value) return onEdit();
142178
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;
144186
};
145187
146188
onMounted(async () => {
@@ -149,6 +191,7 @@ onMounted(async () => {
149191
async val => {
150192
await wait(delay.value);
151193
_progress.value = val;
194+
if (!editing.value) angleProgress.value = val;
152195
},
153196
{ immediate: true },
154197
);
@@ -188,15 +231,18 @@ onBeforeUnmount(() => {
188231
type="circle"
189232
:percentage="editProgress"
190233
:style="{
191-
'--duration': `${ progressDuration }ms`,
192-
'--custom-progress-color': `var(--${ color })`,
234+
'--duration': `${progressDuration}ms`,
235+
'--custom-progress-color': `var(--${color})`,
193236
}"
194237
:tabindex="editable ? 0 : undefined"
195238
@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"
197243
@touchstart="onClick"
198244
@touchend="onClick"
199-
@blur="editing = false"
245+
@blur="onBlur"
200246
>
201247
<span v-if="editing">{{ emitProgress }}</span>
202248
<AnimatedNumber
@@ -227,10 +273,6 @@ onBeforeUnmount(() => {
227273
228274
.custom-color {
229275
--n-fill-color: var(--custom-progress-color, var(--color-info)) !important;
230-
231-
&:focus-visible {
232-
outline: -webkit-focus-ring-color auto 1px;
233-
}
234276
}
235277
236278
.spin {
@@ -245,6 +287,13 @@ onBeforeUnmount(() => {
245287
246288
.progress {
247289
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+
}
248297
249298
:deep(path.n-progress-graph-circle-fill) {
250299
transition:

0 commit comments

Comments
 (0)