mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-19 05:32:16 +01:00
improve time picker focus handling and number input, fixes ST-251
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { getDayJsInstance, getLocalizedDayJs } from '@/utils/time';
|
import { getDayJsInstance, getLocalizedDayJs } from '@/utils/time';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
import { useFocus } from '@vueuse/core';
|
||||||
|
|
||||||
// This has to be a localized timestamp, not UTC
|
// This has to be a localized timestamp, not UTC
|
||||||
const model = defineModel<string | null>({
|
const model = defineModel<string | null>({
|
||||||
@@ -11,19 +12,31 @@ const model = defineModel<string | null>({
|
|||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
size: 'base' | 'large';
|
size: 'base' | 'large';
|
||||||
|
focus: boolean;
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
size: 'base',
|
size: 'base',
|
||||||
|
focus: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const hours = computed(() => {
|
const hours = ref(
|
||||||
return model.value ? getLocalizedDayJs(model.value).format('HH') : null;
|
model.value ? getLocalizedDayJs(model.value).format('HH') : null
|
||||||
});
|
);
|
||||||
|
const minutes = ref(
|
||||||
const minutes = computed(() => {
|
model.value ? getLocalizedDayJs(model.value).format('mm') : null
|
||||||
return model.value ? getLocalizedDayJs(model.value).format('mm') : null;
|
);
|
||||||
});
|
watch(
|
||||||
|
() => model.value,
|
||||||
|
() => {
|
||||||
|
hours.value = model.value
|
||||||
|
? getLocalizedDayJs(model.value).format('HH')
|
||||||
|
: null;
|
||||||
|
minutes.value = model.value
|
||||||
|
? getLocalizedDayJs(model.value).format('mm')
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
function updateMinutes(event: Event) {
|
function updateMinutes(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
@@ -33,19 +46,31 @@ function updateMinutes(event: Event) {
|
|||||||
.set('minutes', Math.min(parseInt(newValue), 59))
|
.set('minutes', Math.min(parseInt(newValue), 59))
|
||||||
.format();
|
.format();
|
||||||
}
|
}
|
||||||
|
minutes.value = model.value
|
||||||
|
? getLocalizedDayJs(model.value).format('mm')
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHours(event: Event) {
|
function updateHours(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
const newValue = target.value;
|
const newValue = target.value;
|
||||||
if (!isNaN(parseInt(newValue))) {
|
if (newValue.endsWith(':')) {
|
||||||
|
minutesInput.value?.focus();
|
||||||
|
} else if (!isNaN(parseInt(newValue))) {
|
||||||
model.value = getLocalizedDayJs(model.value)
|
model.value = getLocalizedDayJs(model.value)
|
||||||
.set('hours', Math.min(parseInt(newValue), 23))
|
.set('hours', Math.min(parseInt(newValue), 23))
|
||||||
.format();
|
.format();
|
||||||
}
|
}
|
||||||
|
hours.value = model.value
|
||||||
|
? getLocalizedDayJs(model.value).format('HH')
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hoursInput = ref<HTMLInputElement | null>(null);
|
||||||
|
const minutesInput = ref<HTMLInputElement | null>(null);
|
||||||
const emit = defineEmits(['changed']);
|
const emit = defineEmits(['changed']);
|
||||||
|
|
||||||
|
useFocus(hoursInput, { initialValue: props.focus });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -58,7 +83,8 @@ const emit = defineEmits(['changed']);
|
|||||||
)
|
)
|
||||||
">
|
">
|
||||||
<input
|
<input
|
||||||
:value="hours"
|
v-model="hours"
|
||||||
|
ref="hoursInput"
|
||||||
@input="updateHours"
|
@input="updateHours"
|
||||||
@keydown.enter="emit('changed')"
|
@keydown.enter="emit('changed')"
|
||||||
@focus="($event.target as HTMLInputElement).select()"
|
@focus="($event.target as HTMLInputElement).select()"
|
||||||
@@ -72,7 +98,8 @@ const emit = defineEmits(['changed']);
|
|||||||
" />
|
" />
|
||||||
<span>:</span>
|
<span>:</span>
|
||||||
<input
|
<input
|
||||||
:value="minutes"
|
v-model="minutes"
|
||||||
|
ref="minutesInput"
|
||||||
@keydown.enter="emit('changed')"
|
@keydown.enter="emit('changed')"
|
||||||
@input="updateMinutes"
|
@input="updateMinutes"
|
||||||
@focus="($event.target as HTMLInputElement).select()"
|
@focus="($event.target as HTMLInputElement).select()"
|
||||||
|
|||||||
@@ -24,7 +24,11 @@ watch(props, () => {
|
|||||||
tempEnd.value = getLocalizedDayJs(props.end).format();
|
tempEnd.value = getLocalizedDayJs(props.end).format();
|
||||||
});
|
});
|
||||||
function updateTimeEntry() {
|
function updateTimeEntry() {
|
||||||
if (tempStart.value !== props.start || tempEnd.value !== props.end) {
|
const tempStartUtc = getDayJsInstance()(tempStart.value).utc().format();
|
||||||
|
const tempEndUtc = tempEnd.value
|
||||||
|
? getDayJsInstance()(tempEnd.value).utc().format()
|
||||||
|
: null;
|
||||||
|
if (tempStartUtc !== props.start || tempEndUtc !== props.end) {
|
||||||
emit(
|
emit(
|
||||||
'changed',
|
'changed',
|
||||||
getDayJsInstance()(tempStart.value).utc().format(),
|
getDayJsInstance()(tempStart.value).utc().format(),
|
||||||
@@ -52,6 +56,7 @@ watch(focused, (newValue, oldValue) => {
|
|||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<TimePicker
|
<TimePicker
|
||||||
data-testid="time_entry_range_start"
|
data-testid="time_entry_range_start"
|
||||||
|
focus
|
||||||
@changed="updateTimeEntry"
|
@changed="updateTimeEntry"
|
||||||
v-model="tempStart"></TimePicker>
|
v-model="tempStart"></TimePicker>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
|
|||||||
Reference in New Issue
Block a user