@@ -8,7 +8,17 @@ import InputModal from '../Modal';
8
8
export type TimePickerProps = InputProps & {
9
9
hours ?: number ;
10
10
minutes ?: number ;
11
- onTimeChange : ( { hours, minutes } : { hours : number ; minutes : number } ) => void ;
11
+ seconds ?: number ;
12
+ displaySeconds ?: boolean ;
13
+ onTimeChange : ( {
14
+ hours,
15
+ minutes,
16
+ seconds,
17
+ } : {
18
+ hours : number ;
19
+ minutes : number ;
20
+ seconds ?: number ;
21
+ } ) => void ;
12
22
} ;
13
23
14
24
type TimeRangeProps = {
@@ -32,7 +42,14 @@ const TimeRange = ({ range, selectedItem, className, onSelectItem }: TimeRangePr
32
42
</ div >
33
43
) ;
34
44
35
- const TimePicker = ( { onTimeChange, hours = 0 , minutes = 0 , ...otherProps } : TimePickerProps ) => {
45
+ const TimePicker = ( {
46
+ onTimeChange,
47
+ hours = 0 ,
48
+ minutes = 0 ,
49
+ seconds = 0 ,
50
+ displaySeconds,
51
+ ...otherProps
52
+ } : TimePickerProps ) => {
36
53
const [ isModalOpen , setIsModalOpen ] = useState < boolean > ( false ) ;
37
54
const inputRef = useRef < HTMLInputElement > ( null ) ;
38
55
@@ -42,28 +59,61 @@ const TimePicker = ({ onTimeChange, hours = 0, minutes = 0, ...otherProps }: Tim
42
59
43
60
if ( newMinutes >= 60 ) {
44
61
newMinutes = 0 ;
45
- newHours = newHours === 23 ? 0 : newHours + 1 ;
62
+ newHours = ( newHours + 1 ) % 24 ;
46
63
} else if ( newMinutes < 0 ) {
47
64
newMinutes = 59 ;
48
- newHours = newHours === 0 ? 23 : newHours - 1 ;
65
+ newHours = ( newHours + 23 ) % 24 ; // minus 1 hour
49
66
}
50
- onTimeChange ( { hours : newHours , minutes : newMinutes } ) ;
67
+ onTimeChange ( { hours : newHours , minutes : newMinutes , seconds } ) ;
68
+ } ;
69
+
70
+ const incrementSeconds = ( increment : number ) => {
71
+ let newSeconds = seconds + increment ;
72
+ let newMinutes = minutes ;
73
+ let newHours = hours ;
74
+
75
+ if ( newSeconds >= 60 ) {
76
+ newSeconds = 0 ;
77
+ newMinutes += 1 ;
78
+
79
+ if ( newMinutes >= 60 ) {
80
+ newMinutes = 0 ;
81
+ newHours = ( newHours + 1 ) % 24 ;
82
+ }
83
+ } else if ( newSeconds < 0 ) {
84
+ newSeconds = 59 ;
85
+ newMinutes -= 1 ;
86
+
87
+ if ( newMinutes < 0 ) {
88
+ newMinutes = 59 ;
89
+ newHours = ( newHours + 23 ) % 24 ; // minus 1 hour
90
+ }
91
+ }
92
+ onTimeChange ( { hours : newHours , minutes : newMinutes , seconds : newSeconds } ) ;
51
93
} ;
52
94
53
95
const handleChange = ( event : React . ChangeEvent < HTMLInputElement > ) => {
54
96
const value = event . target . value ;
55
- const [ h , m ] = value . split ( ':' ) ;
56
- if ( h !== undefined && m !== undefined ) {
57
- onTimeChange ( { hours : parseInt ( h ) , minutes : parseInt ( m ) } ) ;
97
+ if ( ! displaySeconds ) {
98
+ const [ h , m ] = value . split ( ':' ) ;
99
+ if ( h !== undefined && m !== undefined ) {
100
+ onTimeChange ( { hours : parseInt ( h ) , minutes : parseInt ( m ) } ) ;
101
+ }
102
+ } else {
103
+ const [ h , m , s ] = value . split ( ':' ) ;
104
+ if ( h !== undefined && m !== undefined && s !== undefined ) {
105
+ onTimeChange ( { hours : parseInt ( h ) , minutes : parseInt ( m ) , seconds : parseInt ( s ) } ) ;
106
+ }
58
107
}
59
108
} ;
60
109
61
110
const formatTimeValue = ( value : number , max : number ) =>
62
111
Math . max ( 0 , Math . min ( max , value ) ) . toString ( ) . padStart ( 2 , '0' ) ;
63
112
64
- const selectedTime = `${ formatTimeValue ( hours , 23 ) } :${ formatTimeValue ( minutes , 59 ) } ` ;
113
+ const displayedSecondsPart = displaySeconds ? `:${ formatTimeValue ( seconds , 59 ) } ` : '' ;
114
+ const selectedTime = `${ formatTimeValue ( hours , 23 ) } :${ formatTimeValue ( minutes , 59 ) } ${ displayedSecondsPart } ` ;
65
115
const hoursRange = [ ...Array ( 24 ) . keys ( ) ] ;
66
- const minutesRange = [ ...Array ( 12 ) . keys ( ) ] . map ( ( i ) => i * 5 ) ;
116
+ const minutesAndSecondsRange = [ ...Array ( 12 ) . keys ( ) ] . map ( ( i ) => i * 5 ) ;
67
117
68
118
const openModal = ( ) => {
69
119
setIsModalOpen ( true ) ;
@@ -74,12 +124,14 @@ const TimePicker = ({ onTimeChange, hours = 0, minutes = 0, ...otherProps }: Tim
74
124
return (
75
125
< div className = "time-picker" >
76
126
< Input
127
+ className = { cx ( 'input' , 'time-input' ) }
77
128
type = "time"
78
129
name = "time"
79
130
value = { selectedTime }
80
131
onClick = { openModal }
81
132
onChange = { handleChange }
82
133
ref = { inputRef }
134
+ step = { displaySeconds ? 1 : 60 }
83
135
{ ...otherProps }
84
136
/>
85
137
< InputModal inputRef = { inputRef } isOpen = { isModalOpen } onClose = { closeModal } >
@@ -88,17 +140,17 @@ const TimePicker = ({ onTimeChange, hours = 0, minutes = 0, ...otherProps }: Tim
88
140
range = { hoursRange }
89
141
selectedItem = { hours }
90
142
className = "hour"
91
- onSelectItem = { ( h ) => onTimeChange ( { hours : h , minutes } ) }
143
+ onSelectItem = { ( h ) => onTimeChange ( { hours : h , minutes, seconds } ) }
92
144
/>
93
145
94
146
< div className = "time-separator" > :</ div >
95
147
96
148
< div className = "minute-container" >
97
149
< TimeRange
98
- range = { minutesRange }
150
+ range = { minutesAndSecondsRange }
99
151
selectedItem = { minutes }
100
152
className = "minute"
101
- onSelectItem = { ( m ) => onTimeChange ( { hours : hours , minutes : m } ) }
153
+ onSelectItem = { ( m ) => onTimeChange ( { hours, minutes : m , seconds } ) }
102
154
/>
103
155
< div className = "minute-buttons" >
104
156
< button onClick = { ( ) => incrementMinute ( - 1 ) } className = "minute-button" >
@@ -109,6 +161,27 @@ const TimePicker = ({ onTimeChange, hours = 0, minutes = 0, ...otherProps }: Tim
109
161
</ button >
110
162
</ div >
111
163
</ div >
164
+ { displaySeconds && (
165
+ < >
166
+ < div className = "time-separator" > :</ div >
167
+ < div className = "second-container" >
168
+ < TimeRange
169
+ range = { minutesAndSecondsRange }
170
+ selectedItem = { seconds }
171
+ className = "second"
172
+ onSelectItem = { ( s ) => onTimeChange ( { hours, minutes, seconds : s } ) }
173
+ />
174
+ < div className = "second-buttons" >
175
+ < button onClick = { ( ) => incrementSeconds ( - 1 ) } className = "second-button" >
176
+ -1s
177
+ </ button >
178
+ < button onClick = { ( ) => incrementSeconds ( 1 ) } className = "second-button" >
179
+ +1s
180
+ </ button >
181
+ </ div >
182
+ </ div >
183
+ </ >
184
+ ) }
112
185
</ div >
113
186
</ InputModal >
114
187
</ div >
0 commit comments