@@ -12,7 +12,14 @@ import type {
1212 DateFieldSectionType ,
1313 DateFieldSectionWithoutPosition ,
1414} from '../types' ;
15- import { splitFormatIntoSections } from '../utils' ;
15+ import {
16+ addSegment ,
17+ getDurationUnitFromSectionType ,
18+ getSectionLimits ,
19+ getSectionValue ,
20+ setSegment ,
21+ splitFormatIntoSections ,
22+ } from '../utils' ;
1623
1724export interface DateFieldStateOptions extends DateFieldBase { }
1825
@@ -27,12 +34,6 @@ const EDITABLE_SEGMENTS: Partial<Record<DateFieldSectionType, boolean>> = {
2734 weekday : true ,
2835} ;
2936
30- const TYPE_MAPPING = {
31- weekday : 'day' ,
32- day : 'date' ,
33- dayPeriod : 'hour' ,
34- } as const ;
35-
3637const PAGE_STEP : Partial < Record < DateFieldSectionType , number > > = {
3738 year : 5 ,
3839 month : 2 ,
@@ -194,8 +195,13 @@ export function useDateFieldState(props: DateFieldStateOptions): DateFieldState
194195 }
195196
196197 if ( Object . keys ( validSegments ) . length >= Object . keys ( allSegments ) . length ) {
197- setDate ( newValue ) ;
198+ if ( ! value || ! newValue . isSame ( value ) ) {
199+ setDate ( newValue ) ;
200+ }
198201 } else {
202+ if ( value ) {
203+ setDate ( null ) ;
204+ }
199205 setPlaceholderDate ( newValue ) ;
200206 }
201207 }
@@ -396,9 +402,6 @@ export function useDateFieldState(props: DateFieldStateOptions): DateFieldState
396402 currentValue = displayValue . set ( type , placeholder [ type ] ( ) ) ;
397403 }
398404
399- if ( value ) {
400- setDate ( null ) ;
401- }
402405 setValue ( currentValue ) ;
403406 } ,
404407 clearAll ( ) {
@@ -534,6 +537,7 @@ export function useDateFieldState(props: DateFieldStateOptions): DateFieldState
534537 }
535538 } ,
536539 setValueFromString ( str : string ) {
540+ enteredKeys . current = '' ;
537541 let date = parseDate ( { input : str , format, timeZone : props . timeZone } ) ;
538542 if ( isValid ( date ) ) {
539543 if ( props . timeZone && ! isDateStringWithTimeZone ( str ) ) {
@@ -560,65 +564,6 @@ function isDateStringWithTimeZone(str: string) {
560564 return / z $ / i. test ( str ) || / [ + - ] \d \d : \d \d $ / . test ( str ) ;
561565}
562566
563- function addSegment ( section : DateFieldSection , date : DateTime , amount : number ) {
564- let val = section . value ?? 0 ;
565- if ( section . type === 'dayPeriod' ) {
566- val = date . hour ( ) + ( date . hour ( ) > 12 ? - 12 : 12 ) ;
567- } else {
568- val = val + amount ;
569- const min = section . minValue ;
570- const max = section . maxValue ;
571- if ( typeof min === 'number' && typeof max === 'number' ) {
572- const length = max - min + 1 ;
573- val = ( ( val - min + length ) % length ) + min ;
574- }
575- }
576- const type = getDurationUnitFromSectionType ( section . type ) ;
577- return date . set ( type , val ) ;
578- }
579-
580- function setSegment ( section : DateFieldSection , date : DateTime , amount : number ) {
581- const type = section . type ;
582- switch ( type ) {
583- case 'day' :
584- case 'weekday' :
585- case 'month' :
586- case 'year' : {
587- return date . set ( getDurationUnitFromSectionType ( type ) , amount ) ;
588- }
589- case 'dayPeriod' : {
590- const hours = date . hour ( ) ;
591- const wasPM = hours >= 12 ;
592- const isPM = amount >= 12 ;
593- if ( isPM === wasPM ) {
594- return date ;
595- }
596- return date . set ( 'hour' , wasPM ? hours - 12 : hours + 12 ) ;
597- }
598- case 'hour' : {
599- // In 12 hour time, ensure that AM/PM does not change
600- let sectionAmount = amount ;
601- if ( section . minValue === 12 || section . maxValue === 11 ) {
602- const hours = date . hour ( ) ;
603- const wasPM = hours >= 12 ;
604- if ( ! wasPM && sectionAmount === 12 ) {
605- sectionAmount = 0 ;
606- }
607- if ( wasPM && sectionAmount < 12 ) {
608- sectionAmount += 12 ;
609- }
610- }
611- return date . set ( 'hour' , sectionAmount ) ;
612- }
613- case 'minute' :
614- case 'second' : {
615- return date . set ( type , amount ) ;
616- }
617- }
618-
619- return date ;
620- }
621-
622567function getCurrentEditableSectionIndex (
623568 sections : DateFieldSection [ ] ,
624569 selectedSections : 'all' | number ,
@@ -690,20 +635,26 @@ function getEditableSections(
690635 let renderedValue = section . placeholder ;
691636 if ( ( isEditable && validSegments [ section . type ] ) || section . type === 'timeZoneName' ) {
692637 renderedValue = value . format ( section . format ) ;
638+ if (
639+ section . contentType === 'digit' &&
640+ renderedValue . length < section . placeholder . length
641+ ) {
642+ renderedValue = renderedValue . padStart ( section . placeholder . length , '0' ) ;
643+ }
693644 }
694645
695646 const sectionLength = renderedValue . length ;
696647
697648 const newSection = {
698649 ...section ,
699- value : getValue ( value , section . type ) ,
650+ value : getSectionValue ( section , value ) ,
700651 textValue : renderedValue ,
701652 start : position ,
702653 end : position + sectionLength ,
703654 modified : false ,
704655 previousEditableSection,
705656 nextEditableSection : previousEditableSection ,
706- ...getSectionLimits ( value , section . type , { hour12 : isHour12 ( section ) } ) ,
657+ ...getSectionLimits ( section , value ) ,
707658 } ;
708659
709660 newSections . push ( newSection ) ;
@@ -726,97 +677,3 @@ function getEditableSections(
726677
727678 return newSections ;
728679}
729-
730- function getValue ( date : DateTime , type : DateFieldSectionType ) {
731- switch ( type ) {
732- case 'year' :
733- case 'month' :
734- case 'hour' :
735- case 'minute' :
736- case 'second' : {
737- return date [ type ] ( ) ;
738- }
739- case 'day' : {
740- return date . date ( ) ;
741- }
742- case 'weekday' : {
743- return date . day ( ) ;
744- }
745- case 'dayPeriod' : {
746- return date . hour ( ) >= 12 ? 12 : 0 ;
747- }
748- }
749- return undefined ;
750- }
751-
752- function isHour12 ( section : DateFieldSectionWithoutPosition ) {
753- if ( section . type === 'hour' ) {
754- return dateTime ( ) . set ( 'hour' , 15 ) . format ( section . format ) !== '15' ;
755- }
756- return false ;
757- }
758-
759- function getSectionLimits ( date : DateTime , type : DateFieldSectionType , options : { hour12 : boolean } ) {
760- switch ( type ) {
761- case 'year' : {
762- return {
763- minValue : 1 ,
764- maxValue : 9999 ,
765- } ;
766- }
767- case 'month' : {
768- return {
769- minValue : 0 ,
770- maxValue : 11 ,
771- } ;
772- }
773- case 'weekday' : {
774- return {
775- minValue : 0 ,
776- maxValue : 6 ,
777- } ;
778- }
779- case 'day' : {
780- return {
781- minValue : 1 ,
782- maxValue : date ? date . daysInMonth ( ) : 31 ,
783- } ;
784- }
785- case 'hour' : {
786- if ( options . hour12 ) {
787- const isPM = date . hour ( ) >= 12 ;
788- return {
789- minValue : isPM ? 12 : 0 ,
790- maxValue : isPM ? 23 : 11 ,
791- } ;
792- }
793- return {
794- minValue : 0 ,
795- maxValue : 23 ,
796- } ;
797- }
798- case 'minute' :
799- case 'second' : {
800- return {
801- minValue : 0 ,
802- maxValue : 59 ,
803- } ;
804- }
805- }
806- return { } ;
807- }
808-
809- function getDurationUnitFromSectionType ( type : DateFieldSectionType ) {
810- if ( type === 'literal' || type === 'timeZoneName' || type === 'unknown' ) {
811- throw new Error ( `${ type } section does not have duration unit.` ) ;
812- }
813-
814- if ( type in TYPE_MAPPING ) {
815- return TYPE_MAPPING [ type as keyof typeof TYPE_MAPPING ] ;
816- }
817-
818- return type as Exclude <
819- DateFieldSectionType ,
820- keyof typeof TYPE_MAPPING | 'literal' | 'timeZoneName' | 'unknown'
821- > ;
822- }
0 commit comments