diff --git a/packages/nc-gui/components/cell/DatePicker.vue b/packages/nc-gui/components/cell/DatePicker.vue index 8e1bb6c251..2b9958e8c1 100644 --- a/packages/nc-gui/components/cell/DatePicker.vue +++ b/packages/nc-gui/components/cell/DatePicker.vue @@ -68,23 +68,41 @@ const localState = computed({ set(val?: dayjs.Dayjs) { isClearedInputMode.value = false - if (!val) { - emit('update:modelValue', null) + saveChanges(val) + + open.value = false + }, +}) + +const savingValue = ref() + +function saveChanges(val?: dayjs.Dayjs, saveOnChange = true) { + if (!val) { + if (savingValue.value === val) { return } - if (picker.value === 'month') { - // reset day to 1st - val = dayjs(val).date(1) - } + savingValue.value = null + emit('update:modelValue', null) + return + } + + if (picker.value === 'month') { + // reset day to 1st + val = dayjs(val).date(1) + } + + if (val.isValid()) { + const formattedValue = val?.format('YYYY-MM-DD') - if (val.isValid()) { - emit('update:modelValue', val?.format('YYYY-MM-DD')) + if (savingValue.value === formattedValue) { + return } - open.value = false - }, -}) + savingValue.value = formattedValue + emit('update:modelValue', formattedValue) + } +} watchEffect(() => { if (localState.value) { @@ -102,6 +120,12 @@ onClickOutside(datePickerRef, (e) => { }) const onBlur = (e) => { + const value = (e?.target as HTMLInputElement)?.value + + if (value && dayjs(value).isValid()) { + handleUpdateValue(e, true, dayjs(dayjs(value).format(dateFormat.value))) + } + if ( (e?.relatedTarget as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) || (e?.target as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) @@ -263,8 +287,8 @@ useEventListener(document, 'keydown', (e: KeyboardEvent) => { } }) -const handleUpdateValue = (e: Event) => { - const targetValue = (e.target as HTMLInputElement).value +const handleUpdateValue = (e: Event, save = false, valueToSave?: dayjs.Dayjs) => { + const targetValue = valueToSave || (e.target as HTMLInputElement).value if (!targetValue) { tempDate.value = undefined return @@ -273,6 +297,10 @@ const handleUpdateValue = (e: Event) => { if (value.isValid()) { tempDate.value = value + + if (save) { + saveChanges(value, false) + } } } diff --git a/packages/nc-gui/components/cell/DateTimePicker.vue b/packages/nc-gui/components/cell/DateTimePicker.vue index 1824fe7dbf..d69ba43d7f 100644 --- a/packages/nc-gui/components/cell/DateTimePicker.vue +++ b/packages/nc-gui/components/cell/DateTimePicker.vue @@ -121,20 +121,44 @@ const localState = computed({ }, set(val?: dayjs.Dayjs) { isClearedInputMode.value = false - if (!val) { - emit('update:modelValue', null) + saveChanges(val) + }, +}) + +const savingValue = ref() + +function saveChanges(val?: dayjs.Dayjs, saveOnChange = false) { + if (!val) { + if (savingValue.value === null) { return } - if (val.isValid()) { - // setting localModelValue to cater NOW function in date picker - localModelValue = dayjs(val) - // send the payload in UTC format - emit('update:modelValue', dayjs(val).utc().format('YYYY-MM-DD HH:mm:ssZ')) + savingValue.value = null + emit('update:modelValue', null) + + return + } + + if (saveOnChange && localState.value?.isSame(val)) { + return + } + + if (val.isValid()) { + // setting localModelValue to cater NOW function in date picker + localModelValue = dayjs(val) + // send the payload in UTC format + + const formattedValue = dayjs(val).utc().format('YYYY-MM-DD HH:mm:ssZ') + + if (savingValue.value === formattedValue) { + return } - }, -}) + + savingValue.value = formattedValue + emit('update:modelValue', formattedValue) + } +} watchEffect(() => { if (localState.value) { @@ -167,6 +191,10 @@ const onFocus = (_isDatePicker: boolean) => { open.value = true } +const onBlur = (e: Event, _isDatePicker: boolean) => { + handleUpdateValue(e, _isDatePicker, true) +} + watch( open, (next) => { @@ -324,7 +352,7 @@ watch(editable, (nextValue) => { } }) -const handleUpdateValue = (e: Event, _isDatePicker: boolean) => { +const handleUpdateValue = (e: Event, _isDatePicker: boolean, save = false) => { let targetValue = (e.target as HTMLInputElement).value if (_isDatePicker) { @@ -341,6 +369,10 @@ const handleUpdateValue = (e: Event, _isDatePicker: boolean) => { } else { tempDate.value = date } + + if (save) { + saveChanges(tempDate.value, true) + } } } @@ -365,6 +397,10 @@ const handleUpdateValue = (e: Event, _isDatePicker: boolean) => { if (parsedDate.isValid()) { tempDate.value = dayjs(`${(tempDate.value ?? dayjs()).format('YYYY-MM-DD')} ${parsedDate.format(timeFormat.value)}`) + + if (save) { + saveChanges(tempDate.value, true) + } } } } @@ -460,6 +496,7 @@ const currentDate = ($event) => { class="nc-date-input w-full !truncate border-transparent outline-none !text-current !bg-transparent !focus:(border-none outline-none ring-transparent)" :readonly="!!isMobileMode || isColDisabled" @focus="onFocus(true)" + @blur="onBlur($event, true)" @keydown="handleKeydown($event, isOpen, true)" @mouseup.stop @mousedown.stop @@ -486,6 +523,7 @@ const currentDate = ($event) => { class="nc-time-input w-full !truncate border-transparent outline-none !text-current !bg-transparent !focus:(border-none outline-none ring-transparent)" :readonly="!!isMobileMode || isColDisabled" @focus="onFocus(false)" + @blur="onBlur($event, false)" @keydown="handleKeydown($event, open)" @mouseup.stop @mousedown.stop diff --git a/packages/nc-gui/components/cell/TimePicker.vue b/packages/nc-gui/components/cell/TimePicker.vue index 8b941bcecb..0504dcbcff 100644 --- a/packages/nc-gui/components/cell/TimePicker.vue +++ b/packages/nc-gui/components/cell/TimePicker.vue @@ -69,18 +69,39 @@ const localState = computed({ }, set(val?: dayjs.Dayjs) { isClearedInputMode.value = false - if (!val) { - emit('update:modelValue', null) + + saveChanges(val) + }, +}) + +const savingValue = ref() + +function saveChanges(val?: dayjs.Dayjs) { + if (!val) { + if (savingValue.value === val) { return } - if (val.isValid()) { - const time = val.format('HH:mm') - const date = dayjs(`1999-01-01 ${time}:00`) - emit('update:modelValue', date.format(dateFormat)) + savingValue.value = null + + emit('update:modelValue', null) + return + } + + if (val.isValid()) { + const time = val.format('HH:mm') + const date = dayjs(`1999-01-01 ${time}:00`) + + const formattedValue = date.format(dateFormat) + + if (savingValue.value === formattedValue) { + return } - }, -}) + + savingValue.value = formattedValue + emit('update:modelValue', date.format(dateFormat)) + } +} watchEffect(() => { if (localState.value) { @@ -97,6 +118,8 @@ onClickOutside(datePickerRef, (e) => { }) const onBlur = (e) => { + handleUpdateValue(e, true) + if ( (e?.relatedTarget as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) || (e?.target as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) @@ -246,7 +269,7 @@ useEventListener(document, 'keydown', (e: KeyboardEvent) => { } }) -const handleUpdateValue = (e: Event) => { +const handleUpdateValue = (e: Event, save = false) => { let targetValue = (e.target as HTMLInputElement).value if (!targetValue) { @@ -266,6 +289,10 @@ const handleUpdateValue = (e: Event) => { if (parsedDate.isValid()) { tempDate.value = dayjs(`${dayjs().format('YYYY-MM-DD')} ${parsedDate.format('HH:mm')}`) + + if (save) { + saveChanges(tempDate.value) + } } } diff --git a/packages/nc-gui/components/cell/YearPicker.vue b/packages/nc-gui/components/cell/YearPicker.vue index b87dfeb768..61d5c7ce89 100644 --- a/packages/nc-gui/components/cell/YearPicker.vue +++ b/packages/nc-gui/components/cell/YearPicker.vue @@ -60,18 +60,38 @@ const localState = computed({ set(val?: dayjs.Dayjs) { isClearedInputMode.value = false - if (!val) { - emit('update:modelValue', null) + saveChanges(val) + + open.value = false + }, +}) + +const savingValue = ref() + +function saveChanges(val?: dayjs.Dayjs) { + if (!val) { + if (savingValue.value === val) { return } - if (val?.isValid()) { - emit('update:modelValue', val.format('YYYY')) + savingValue.value = null + + emit('update:modelValue', null) + return + } + + if (val?.isValid()) { + const formattedValue = val.format('YYYY') + + if (savingValue.value === formattedValue) { + return } - open.value = false - }, -}) + savingValue.value = formattedValue + + emit('update:modelValue', val.format('YYYY')) + } +} watchEffect(() => { if (localState.value) { @@ -88,6 +108,12 @@ onClickOutside(datePickerRef, (e) => { }) const onBlur = (e) => { + const value = (e?.target as HTMLInputElement)?.value + + if (value && dayjs(value, 'YYYY').isValid()) { + handleUpdateValue(e, true, dayjs(dayjs(value).format('YYYY'))) + } + if ( (e?.relatedTarget as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) || (e?.target as HTMLElement)?.closest(`.${randomClass}, .nc-${randomClass}`) @@ -227,8 +253,8 @@ useEventListener(document, 'keydown', (e: KeyboardEvent) => { } }) -const handleUpdateValue = (e: Event) => { - const targetValue = (e.target as HTMLInputElement).value +const handleUpdateValue = (e: Event, save = false, valueToSave?: dayjs.Dayjs) => { + const targetValue = valueToSave || (e.target as HTMLInputElement).value if (!targetValue) { tempDate.value = undefined return @@ -237,6 +263,10 @@ const handleUpdateValue = (e: Event) => { if (value.isValid()) { tempDate.value = value + + if (save) { + saveChanges(value) + } } }