Skip to content

Commit 410d192

Browse files
committed
refactor(date-input): rename rangeTimeSelectDisabled to isRangeTimeSelectDisabled and update related logic
1 parent 10ca9b2 commit 410d192

1 file changed

Lines changed: 102 additions & 77 deletions

File tree

packages/varlet-ui/src/date-input/DateInput.vue

Lines changed: 102 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
:second="rangeTimes[0].second"
8484
:use-seconds="useSeconds"
8585
:readonly="readonly || formReadonly"
86-
:disabled="disabled || formDisabled || rangeTimeSelectDisabled"
86+
:disabled="disabled || formDisabled || isRangeTimeSelectDisabled"
8787
:is-hour-allowed="startAllowFns.isHourAllowed"
8888
:is-minute-allowed="startAllowFns.isMinuteAllowed"
8989
:is-second-allowed="startAllowFns.isSecondAllowed"
@@ -96,7 +96,7 @@
9696
:second="rangeTimes[1].second"
9797
:use-seconds="useSeconds"
9898
:readonly="readonly || formReadonly"
99-
:disabled="disabled || formDisabled || rangeTimeSelectDisabled"
99+
:disabled="disabled || formDisabled || isRangeTimeSelectDisabled"
100100
:is-hour-allowed="endAllowFns.isHourAllowed"
101101
:is-minute-allowed="endAllowFns.isMinuteAllowed"
102102
:is-second-allowed="endAllowFns.isSecondAllowed"
@@ -206,9 +206,11 @@ export default defineComponent({
206206
const pickerMin = computed(() => getPickerBound(props.min))
207207
const pickerMax = computed(() => getPickerBound(props.max))
208208
const rangeSelecting = computed(() => Boolean(picker.value?.rangeSelecting))
209-
const rangeTimeSelectDisabled = computed(
209+
const isRangeTimeSelectDisabled = computed(
210210
() => isDatetime.value && props.range && (rangeSelecting.value || getDayjsObjectsByModelValue().length < 2),
211211
)
212+
const minDayjsObject = computed(() => (props.min ? dayjs(props.min) : undefined))
213+
const maxDayjsObject = computed(() => (props.max ? dayjs(props.max) : undefined))
212214
const singleTime = computed(() => getTimeParts(getDayjsObjectsByModelValue()[0]))
213215
const rangeTimes = computed(() => {
214216
const dayjsObjects = getDayjsObjectsByModelValue()
@@ -301,21 +303,21 @@ export default defineComponent({
301303
}
302304
303305
function clampDatetime(dayjsObject: Dayjs) {
304-
const minDayjsObject = props.min ? dayjs(props.min) : undefined
305-
const maxDayjsObject = props.max ? dayjs(props.max) : undefined
306+
const min = minDayjsObject.value
307+
const max = maxDayjsObject.value
306308
307-
if (minDayjsObject && dayjsObject.isBefore(minDayjsObject)) {
308-
return minDayjsObject
309+
if (min && dayjsObject.isBefore(min)) {
310+
return min
309311
}
310312
311-
if (maxDayjsObject && dayjsObject.isAfter(maxDayjsObject)) {
312-
return maxDayjsObject
313+
if (max && dayjsObject.isAfter(max)) {
314+
return max
313315
}
314316
315317
return dayjsObject
316318
}
317319
318-
function createTimeAllowFns(
320+
function createTimeSelectValidators(
319321
getDayjsObjectByModelValue: () => Dayjs | undefined,
320322
getTimeParts: () => TimeParts,
321323
position?: DateInputRangePosition,
@@ -333,14 +335,14 @@ export default defineComponent({
333335
.minute(unit === 'minute' ? value : time.minute)
334336
.second(unit === 'second' ? value : time.second)
335337
336-
const minDayjsObject = props.min ? dayjs(props.min) : undefined
337-
const maxDayjsObject = props.max ? dayjs(props.max) : undefined
338+
const min = minDayjsObject.value
339+
const max = maxDayjsObject.value
338340
339-
if (minDayjsObject && timeOptionDayjsObject.endOf(unit).isBefore(minDayjsObject)) {
341+
if (min && timeOptionDayjsObject.endOf(unit).isBefore(min)) {
340342
return false
341343
}
342344
343-
if (maxDayjsObject && timeOptionDayjsObject.startOf(unit).isAfter(maxDayjsObject)) {
345+
if (max && timeOptionDayjsObject.startOf(unit).isAfter(max)) {
344346
return false
345347
}
346348
@@ -364,16 +366,16 @@ export default defineComponent({
364366
}
365367
}
366368
367-
const singleAllowFns = createTimeAllowFns(
369+
const singleAllowFns = createTimeSelectValidators(
368370
() => getDayjsObjectsByModelValue()[0],
369371
() => singleTime.value,
370372
)
371-
const startAllowFns = createTimeAllowFns(
373+
const startAllowFns = createTimeSelectValidators(
372374
() => getDayjsObjectsByModelValue()[0],
373375
() => rangeTimes.value[0],
374376
'start',
375377
)
376-
const endAllowFns = createTimeAllowFns(
378+
const endAllowFns = createTimeSelectValidators(
377379
() => getDayjsObjectsByModelValue()[1],
378380
() => rangeTimes.value[1],
379381
'end',
@@ -392,15 +394,15 @@ export default defineComponent({
392394
}
393395
394396
function isTimeCandidateAllowed(candidateDayjsObject: Dayjs, validators: DateInputAllowedTimeValidators) {
395-
const minDayjsObject = props.min ? dayjs(props.min) : undefined
396-
const maxDayjsObject = props.max ? dayjs(props.max) : undefined
397+
const min = minDayjsObject.value
398+
const max = maxDayjsObject.value
397399
const hour = candidateDayjsObject.hour()
398400
const minute = candidateDayjsObject.minute()
399401
const second = candidateDayjsObject.second()
400402
401403
return (
402-
(!minDayjsObject || !candidateDayjsObject.isBefore(minDayjsObject)) &&
403-
(!maxDayjsObject || !candidateDayjsObject.isAfter(maxDayjsObject)) &&
404+
(!min || !candidateDayjsObject.isBefore(min)) &&
405+
(!max || !candidateDayjsObject.isAfter(max)) &&
404406
(!validators.hours || validators.hours(hour)) &&
405407
(!validators.minutes || validators.minutes(minute, hour)) &&
406408
(!props.useSeconds || !validators.seconds || validators.seconds(second, minute, hour)) &&
@@ -447,24 +449,33 @@ export default defineComponent({
447449
}
448450
}
449451
452+
function normalizeDateTimes(dayjsObjects: Dayjs[]) {
453+
// Picker and TimeSelect are controlled selection paths, so range values are normalized to [start, end] here.
454+
// Manual input does not use this sorter. A reversed range remains invalid and is not committed.
455+
return props.range ? [...dayjsObjects].sort((a, b) => a.valueOf() - b.valueOf()) : dayjsObjects
456+
}
457+
450458
function commitDateTimes(dayjsObjects: Dayjs[]) {
451-
if (props.range) {
452-
const sorted = [...dayjsObjects].sort((a, b) => a.valueOf() - b.valueOf())
459+
const nextDayjsObjects = normalizeDateTimes(dayjsObjects)
453460
454-
if (!isDayjsObjectSelectable(sorted[0], 'start') || !isDayjsObjectSelectable(sorted[1], 'end')) {
461+
if (props.range) {
462+
if (
463+
!isDayjsObjectSelectable(nextDayjsObjects[0], 'start') ||
464+
!isDayjsObjectSelectable(nextDayjsObjects[1], 'end')
465+
) {
455466
return false
456467
}
457468
458-
pickerValue.value = sorted.map((dayjsObject) => dayjsObject.format(getPickerFormat()))
459-
displayValue.value = sorted
469+
pickerValue.value = nextDayjsObjects.map((dayjsObject) => dayjsObject.format(getPickerFormat()))
470+
displayValue.value = nextDayjsObjects
460471
.map((dayjsObject) => dayjsObject.format(getDisplayFormat()))
461472
.join(props.rangeSeparator)
462-
updateModelValue(sorted.map(dayjsObjectToModelValue))
473+
updateModelValue(nextDayjsObjects.map(dayjsObjectToModelValue))
463474
464475
return true
465476
}
466477
467-
const [dayjsObject] = dayjsObjects
478+
const [dayjsObject] = nextDayjsObjects
468479
469480
if (!isDayjsObjectSelectable(dayjsObject)) {
470481
return false
@@ -540,19 +551,16 @@ export default defineComponent({
540551
}
541552
542553
function isDayjsObjectSelectable(dayjsObject: Dayjs, position?: DateInputRangePosition) {
543-
const minDayjsObject = props.min ? dayjs(props.min) : undefined
544-
const maxDayjsObject = props.max ? dayjs(props.max) : undefined
554+
const min = minDayjsObject.value
555+
const max = maxDayjsObject.value
545556
const unit =
546557
props.type === 'year' ? 'year' : props.type === 'month' ? 'month' : props.type === 'date' ? 'day' : undefined
547558
548-
if (
549-
minDayjsObject &&
550-
(unit ? dayjsObject.isBefore(minDayjsObject, unit) : dayjsObject.isBefore(minDayjsObject))
551-
) {
559+
if (min && (unit ? dayjsObject.isBefore(min, unit) : dayjsObject.isBefore(min))) {
552560
return false
553561
}
554562
555-
if (maxDayjsObject && (unit ? dayjsObject.isAfter(maxDayjsObject, unit) : dayjsObject.isAfter(maxDayjsObject))) {
563+
if (max && (unit ? dayjsObject.isAfter(max, unit) : dayjsObject.isAfter(max))) {
556564
return false
557565
}
558566
@@ -704,6 +712,7 @@ export default defineComponent({
704712
705713
const validDayjsObjects = dayjsObjects.filter(isTruthy)
706714
715+
// Manual input keeps the user-provided order. A reversed range is not auto-sorted or committed.
707716
if (props.range && validDayjsObjects[0].isAfter(validDayjsObjects[1])) {
708717
return
709718
}
@@ -741,6 +750,7 @@ export default defineComponent({
741750
return
742751
}
743752
753+
// The input path allows temporary invalid display text and commits only after parsing and validation pass.
744754
if (isMultipleOrRange.value) {
745755
updateMultipleOrRangeStatesByDisplayValue()
746756
} else {
@@ -755,70 +765,70 @@ export default defineComponent({
755765
return
756766
}
757767
768+
// On edit completion, restore from modelValue to clear uncommitted temporary input.
758769
updateDisplayValueByDayjsObjects(getDayjsObjectsByModelValue())
759770
}
760771
761-
function handlePickerChange(value: string | string[]) {
762-
if (isDisabled.value || isReadonly.value) {
772+
function handleDatetimeRangePickerChange(dayjsObjects: Dayjs[]) {
773+
if (dayjsObjects.length < 2) {
763774
return
764775
}
765776
766-
pickerValue.value = value
767-
768-
if (isArray(value)) {
769-
const dayjsObjects = value
770-
.map((item) => dayjs(item, getPickerFormat(), true))
771-
.filter((dayjsObject) => dayjsObject.isValid())
777+
// DatePicker only provides dates. Datetime values must merge the current time before committing.
778+
const times = rangeTimes.value
779+
const resolved = dayjsObjects.map((dayjsObject, index) =>
780+
resolveSelectableDateTime(dayjsObject, times[index] ?? getTimeParts(), index === 0 ? 'start' : 'end'),
781+
)
772782
773-
if (isDatetime.value && props.range) {
774-
if (dayjsObjects.length < 2) {
775-
return
776-
}
783+
if (resolved.every(isTruthy)) {
784+
if (!commitDateTimes(resolved.filter(isTruthy))) {
785+
updateStatesByModelValue()
786+
}
787+
} else {
788+
updateStatesByModelValue()
789+
}
790+
}
777791
778-
const times = rangeTimes.value
779-
const resolved = dayjsObjects.map((dayjsObject, index) =>
780-
resolveSelectableDateTime(dayjsObject, times[index] ?? getTimeParts(), index === 0 ? 'start' : 'end'),
781-
)
792+
function handlePickerArrayChange(value: string[]) {
793+
const dayjsObjects = value
794+
.map((item) => dayjs(item, getPickerFormat(), true))
795+
.filter((dayjsObject) => dayjsObject.isValid())
782796
783-
if (resolved.every(isTruthy)) {
784-
if (!commitDateTimes(resolved.filter(isTruthy))) {
785-
updateStatesByModelValue()
786-
}
787-
} else {
788-
updateStatesByModelValue()
789-
}
797+
if (isDatetime.value && props.range) {
798+
handleDatetimeRangePickerChange(dayjsObjects)
799+
return
800+
}
790801
791-
return
792-
}
802+
const modelValue = dayjsObjects.map(dayjsObjectToModelValue)
793803
794-
const modelValue = dayjsObjects.map(dayjsObjectToModelValue)
804+
displayValue.value = dayjsObjects
805+
.map((dayjsObject) => dayjsObject.format(getDisplayFormat()))
806+
.join(props.range ? props.rangeSeparator : props.separator)
795807
796-
displayValue.value = dayjsObjects
797-
.map((dayjsObject) => dayjsObject.format(getDisplayFormat()))
798-
.join(props.range ? props.rangeSeparator : props.separator)
808+
updateModelValue(modelValue)
809+
}
799810
800-
updateModelValue(modelValue)
811+
function handleDatetimePickerChange(dayjsObject: Dayjs) {
812+
const resolved = resolveSelectableDateTime(dayjsObject, singleTime.value)
801813
802-
return
814+
if (resolved) {
815+
if (!commitDateTimes([resolved])) {
816+
updateStatesByModelValue()
817+
}
818+
} else {
819+
updateStatesByModelValue()
803820
}
821+
}
804822
823+
function handlePickerSingleChange(value: string) {
805824
const dayjsObject = dayjs(value, getPickerFormat(), true)
806825
807826
if (!dayjsObject.isValid()) {
808827
return
809828
}
810829
811830
if (isDatetime.value) {
812-
const resolved = resolveSelectableDateTime(dayjsObject, singleTime.value)
813-
814-
if (resolved) {
815-
if (!commitDateTimes([resolved])) {
816-
updateStatesByModelValue()
817-
}
818-
} else {
819-
updateStatesByModelValue()
820-
}
821-
831+
handleDatetimePickerChange(dayjsObject)
822832
return
823833
}
824834
@@ -830,6 +840,21 @@ export default defineComponent({
830840
}
831841
}
832842
843+
function handlePickerChange(value: string | string[]) {
844+
if (isDisabled.value || isReadonly.value) {
845+
return
846+
}
847+
848+
pickerValue.value = value
849+
850+
if (isArray(value)) {
851+
handlePickerArrayChange(value)
852+
return
853+
}
854+
855+
handlePickerSingleChange(value)
856+
}
857+
833858
function getEmptyModelValue() {
834859
return isMultipleOrRange.value ? [] : undefined
835860
}
@@ -887,7 +912,7 @@ export default defineComponent({
887912
showMenu,
888913
isFocusing,
889914
rangeSelecting,
890-
rangeTimeSelectDisabled,
915+
isRangeTimeSelectDisabled,
891916
formDisabled,
892917
formReadonly,
893918
errorMessage,

0 commit comments

Comments
 (0)