2
2
3
3
import React from 'react' ;
4
4
5
- import type { DateTime } from '@gravity-ui/date-utils' ;
6
- import { Calendar as CalendarIcon } from '@gravity-ui/icons' ;
7
- import {
8
- Button ,
9
- Icon ,
10
- TextInput ,
11
- useControlledState ,
12
- useFocusWithin ,
13
- useMobile ,
14
- } from '@gravity-ui/uikit' ;
5
+ import { useControlledState , useFocusWithin , useMobile } from '@gravity-ui/uikit' ;
15
6
16
7
import { block } from '../../utils/cn' ;
17
8
import { HiddenInput } from '../HiddenInput/HiddenInput' ;
18
9
import type { Value } from '../RelativeDatePicker' ;
19
- import type {
20
- DomProps ,
21
- FocusableProps ,
22
- InputBase ,
23
- InputDOMProps ,
24
- RangeValue ,
25
- StyleProps ,
26
- TextInputProps ,
27
- Validation ,
28
- } from '../types' ;
29
- import { getButtonSizeForInput } from '../utils/getButtonSizeForInput' ;
30
10
11
+ import { Control } from './components/Control/Control' ;
31
12
import { PickerDialog } from './components/PickerDialog/PickerDialog' ;
32
- import type { Preset } from './components/Presets/defaultPresets' ;
33
- import type { PresetTab } from './components/Presets/utils' ;
34
13
import { useRelativeRangeDatePickerState } from './hooks/useRelativeRangeDatePickerState' ;
35
- import type { RelativeRangeDatePickerStateOptions } from './hooks/useRelativeRangeDatePickerState' ;
36
- import { i18n } from './i18n' ;
37
- import { getDefaultTitle } from './utils' ;
14
+ import type { RelativeRangeDatePickerProps } from './types' ;
38
15
39
16
import './RelativeRangeDatePicker.scss' ;
40
17
41
18
const b = block ( 'relative-range-date-picker' ) ;
42
19
43
- export interface RelativeRangeDatePickerProps
44
- extends RelativeRangeDatePickerStateOptions ,
45
- DomProps ,
46
- InputBase ,
47
- InputDOMProps ,
48
- TextInputProps ,
49
- Validation ,
50
- FocusableProps ,
51
- StyleProps {
52
- /** Format of the date when rendered in the input. [Available formats](https://day.js.org/docs/en/display/format) */
53
- format ?: string ;
54
- /** A placeholder date that controls the default values of each segment when the user first interacts with them. Defaults to today's date at midnight. */
55
- placeholderValue ?: DateTime ;
56
- /** Apply changes with button */
57
- withApplyButton ?: boolean ;
58
- /** Show time zone selector */
59
- withZonesList ?: boolean ;
60
- /** Show relative range presets */
61
- withPresets ?: boolean ;
62
- /** Custom preset tabs */
63
- presetTabs ?: PresetTab [ ] ;
64
- /** Custom docs for presets, if empty array docs will be hidden */
65
- docs ?: Preset [ ] ;
66
- /** Show selected relative values as absolute dates */
67
- alwaysShowAsAbsolute ?: boolean ;
68
- /** */
69
- getRangeTitle ?: ( value : RangeValue < Value | null > | null , timeZone : string ) => string ;
70
- /** Sets the CSS className for the popup element. */
71
- popupClassName ?: string ;
72
- /** Handler that is called when the popup's open state changes. */
73
- onOpenChange ?: ( open : boolean ) => void ;
74
- }
75
-
76
20
export function RelativeRangeDatePicker ( props : RelativeRangeDatePickerProps ) {
77
21
const state = useRelativeRangeDatePickerState ( props ) ;
78
22
@@ -99,58 +43,27 @@ export function RelativeRangeDatePicker(props: RelativeRangeDatePickerProps) {
99
43
} ,
100
44
} ) ;
101
45
102
- const { alwaysShowAsAbsolute, presetTabs, getRangeTitle} = props ;
103
- const format = props . format || 'L' ;
104
- const text = React . useMemo (
105
- ( ) =>
106
- typeof getRangeTitle === 'function'
107
- ? getRangeTitle ( state . value , state . timeZone )
108
- : getDefaultTitle ( {
109
- value : state . value ,
110
- timeZone : state . timeZone ,
111
- alwaysShowAsAbsolute : alwaysShowAsAbsolute ,
112
- format,
113
- presets : presetTabs ?. flatMap ( ( { presets} ) => presets ) ,
114
- } ) ,
115
- [ alwaysShowAsAbsolute , format , getRangeTitle , presetTabs , state . timeZone , state . value ] ,
116
- ) ;
117
-
118
- const validationState = props . validationState || ( state . isInvalid ? 'invalid' : undefined ) ;
119
- const errorMessage = props . errorMessage ?? state . errors . join ( '\n' ) ;
120
-
121
46
return (
122
47
< div
123
48
ref = { anchorRef }
124
49
{ ...focusWithinProps }
125
50
className = { b ( null , props . className ) }
126
51
style = { props . style }
127
52
>
128
- < TextInput
129
- id = { props . id }
130
- autoFocus = { props . autoFocus }
131
- controlRef = { inputRef }
132
- value = { text }
133
- placeholder = { props . placeholder }
134
- onUpdate = { ( v ) => {
135
- if ( ! props . readOnly && ! v ) {
136
- state . setValue ( null , 'default' ) ;
53
+ < Control
54
+ props = { props }
55
+ state = { state }
56
+ open = { open }
57
+ isMobile = { isMobile }
58
+ ref = { inputRef }
59
+ onClick = { ( ) => {
60
+ if ( props . disabled ) {
61
+ return ;
62
+ }
63
+ if ( ! open ) {
64
+ setIsActive ( true ) ;
65
+ setOpen ( true ) ;
137
66
}
138
- } }
139
- controlProps = { {
140
- role : 'combobox' ,
141
- 'aria-expanded' : open ,
142
- disabled : isMobile ,
143
- readOnly : props . readOnly ,
144
- className : b ( 'input' , { mobile : isMobile } ) ,
145
- onClick : ( ) => {
146
- if ( props . disabled ) {
147
- return ;
148
- }
149
- if ( ! open ) {
150
- setIsActive ( true ) ;
151
- setOpen ( true ) ;
152
- }
153
- } ,
154
67
} }
155
68
onKeyDown = { ( e ) => {
156
69
if ( props . disabled ) {
@@ -161,52 +74,22 @@ export function RelativeRangeDatePicker(props: RelativeRangeDatePickerProps) {
161
74
setOpen ( true ) ;
162
75
}
163
76
} }
77
+ onClickCalendar = { ( ) => {
78
+ setIsActive ( true ) ;
79
+ setOpen ( ! open ) ;
80
+ } }
164
81
onFocus = { ( ) => {
165
82
if ( ! isActive ) {
166
83
setIsActive ( true ) ;
167
84
setOpen ( true ) ;
168
85
}
169
86
} }
170
- validationState = { validationState }
171
- errorMessage = { errorMessage }
172
- errorPlacement = { props . errorPlacement }
173
- pin = { props . pin }
174
- size = { props . size }
175
- label = { props . label }
176
- hasClear = { props . hasClear }
177
- disabled = { props . disabled }
178
- endContent = {
179
- < Button
180
- view = "flat-secondary"
181
- size = { getButtonSizeForInput ( props . size ) }
182
- disabled = { props . disabled }
183
- extraProps = { {
184
- 'aria-haspopup' : 'dialog' ,
185
- 'aria-expanded' : open ,
186
- 'aria-label' : i18n ( 'Range date picker' ) ,
187
- } }
188
- onClick = { ( ) => {
189
- setIsActive ( true ) ;
190
- setOpen ( ! open ) ;
191
- } }
192
- >
193
- < Icon data = { CalendarIcon } />
194
- </ Button >
195
- }
87
+ onUpdate = { ( v : string ) => {
88
+ if ( ! props . readOnly && ! v ) {
89
+ state . setValue ( null , 'default' ) ;
90
+ }
91
+ } }
196
92
/>
197
- { isMobile ? (
198
- < button
199
- className = { b ( 'mobile-trigger' , {
200
- 'has-clear' : Boolean ( props . hasClear && state . value ) ,
201
- 'has-errors' : state . isInvalid && props . errorPlacement === 'inside' ,
202
- size : props . size ,
203
- } ) }
204
- onClick = { ( ) => {
205
- setIsActive ( true ) ;
206
- setOpen ( true ) ;
207
- } }
208
- />
209
- ) : null }
210
93
< HiddenInput
211
94
name = { props . name }
212
95
form = { props . form }
0 commit comments