Skip to content

Commit d499000

Browse files
authored
Feat/date time picker ts (#1694)
* Convert DateTimePicker to TS * Fix TS error * migrate date time picker screen to tsx * Fix typings issues * Remove redundant import * ignore usages of useCustomTheme for now
1 parent 2fe60d3 commit d499000

File tree

15 files changed

+373
-130
lines changed

15 files changed

+373
-130
lines changed

demo/src/screens/componentScreens/DateTimePickerScreen.js renamed to demo/src/screens/componentScreens/DateTimePickerScreen.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ import {ScrollView} from 'react-native';
33
import {DateTimePicker, Text, TouchableOpacity, Colors} from 'react-native-ui-lib'; // eslint-disable-line
44

55
export default class DateTimePickerScreen extends Component {
6-
7-
getCustomInputValue = value => {
6+
getCustomInputValue = (value: string) => {
87
if (!value) {
98
return 'Default';
109
}
11-
return value.includes(new Date().getFullYear() + 1) ? 'Next Year' : value;
10+
return value.includes((new Date().getFullYear() + 1).toString()) ? 'Next Year' : value;
1211
};
1312

14-
renderCustomInput = (props, toggle) => {
13+
renderCustomInput = (props: {value: string}, toggle: (shouldToggle: boolean) => void) => {
1514
const {value} = props;
1615
return (
1716
<TouchableOpacity
@@ -23,7 +22,9 @@ export default class DateTimePickerScreen extends Component {
2322
}}
2423
>
2524
<Text>Valid from</Text>
26-
<Text absR color={Colors.primary} text80BO>{this.getCustomInputValue(value)}</Text>
25+
<Text absR color={Colors.primary} text80BO>
26+
{this.getCustomInputValue(value)}
27+
</Text>
2728
</TouchableOpacity>
2829
);
2930
};
@@ -33,6 +34,7 @@ export default class DateTimePickerScreen extends Component {
3334
<ScrollView style={{padding: 14}}>
3435
<Text text40>Date Time Picker</Text>
3536
<DateTimePicker
37+
// @ts-expect-error
3638
containerStyle={{marginVertical: 20}}
3739
title={'Date'}
3840
placeholder={'Select a date'}

generatedTypes/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export {default as Chip, ChipProps} from './src/components/chip';
4242
export {default as ColorPicker, ColorPickerProps} from './src/components/colorPicker';
4343
export {default as ColorPalette, ColorPaletteProps} from './src/components/colorPicker/ColorPalette';
4444
export {default as ColorSwatch, ColorSwatchProps} from './src/components/colorPicker/ColorSwatch';
45+
export {default as DateTimePicker, DateTimePickerProps} from './src/components/dateTimePicker';
4546
export {default as Drawer, DrawerProps, DrawerItemProps} from './src/components/drawer';
4647
export {default as ProgressBar, ProgressBarProps} from './src/components/progressBar';
4748
export {default as FeatureHighlight, FeatureHighlightProps} from './src/components/featureHighlight';
@@ -111,5 +112,4 @@ export {
111112
/* All components that are missing either manual or auto generated typings */
112113
export const AnimatedImage;
113114
export const AnimatedScanner;
114-
export const DateTimePicker;
115115
export const TextField;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
declare const validators: {
2+
required: (value: string) => boolean;
3+
email: (value: string) => boolean;
4+
url: (value: string) => boolean;
5+
number: (value: string) => boolean;
6+
price: (value: string) => boolean;
7+
};
8+
export default validators;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import 'react';
2+
import { BaseComponent } from '../../commons';
3+
export default class BaseInput extends BaseComponent {
4+
static displayName: string;
5+
static propTypes: any;
6+
static defaultProps: {
7+
validateOnBlur: boolean;
8+
};
9+
constructor(props: any);
10+
componentDidMount(): void;
11+
/** Events */
12+
onFocus: (...args: any[]) => void;
13+
onBlur: (...args: any[]) => void;
14+
onChange: (event: any) => void;
15+
onChangeText: (text: any) => void;
16+
/** Actions */
17+
getTypography(): any;
18+
hasText(): any;
19+
isFocused(): any;
20+
focus(): void;
21+
blur(): void;
22+
clear(): void;
23+
validate: any;
24+
isRequiredField(): boolean;
25+
getRequiredPlaceholder(placeholder: any): any;
26+
getErrorMessage(): any;
27+
getColor(value: string): string;
28+
toggleExpandableModal(...args: any[]): any;
29+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import React, { Component } from 'react';
2+
import { StyleProp, ViewStyle } from 'react-native';
3+
import { BaseComponentInjectedProps } from '../../commons/new';
4+
import { DialogProps } from '../dialog';
5+
/**
6+
* @description: Date and Time Picker Component that wraps RNDateTimePicker for date and time modes.
7+
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/DateTimePickerScreen.js
8+
* @important: DateTimePicker uses a native library. You MUST add and link the native library to both iOS and Android projects.
9+
* @extends: TextField, react-native-community/datetimepicker
10+
* @extendsLink: https://github.com/react-native-community/react-native-datetimepicker#react-native-datetimepicker
11+
* @gif: https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/DateTimePicker/DateTimePicker_iOS.gif?raw=true, https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/DateTimePicker/DateTimePicker_Android.gif?raw=true
12+
*/
13+
export interface DateTimePickerProps {
14+
/**
15+
* The type of picker to display ('date' or 'time')
16+
*/
17+
mode?: 'date' | 'time';
18+
/**
19+
* The initial value to set the picker to. Defaults to device's date / time
20+
*/
21+
value?: Date;
22+
/**
23+
* The onChange callback
24+
*/
25+
onChange?: (date: Date) => void;
26+
/**
27+
* The minimum date or time value to use
28+
*/
29+
minimumDate?: Date;
30+
/**
31+
* The maximum date or time value to use
32+
*/
33+
maximumDate?: Date;
34+
/**
35+
* The date format for the text display
36+
*/
37+
dateFormat?: string;
38+
/**
39+
* A callback function to format date
40+
*/
41+
dateFormatter?: (date: Date) => string;
42+
/**
43+
* The time format for the text display
44+
*/
45+
timeFormat?: string;
46+
/**
47+
* A callback function to format time
48+
*/
49+
timeFormatter?: (date: Date) => string;
50+
/**
51+
* Allows changing of the locale of the component (iOS only)
52+
*/
53+
locale?: string;
54+
/**
55+
* Allows changing of the time picker to a 24 hour format (Android only)
56+
*/
57+
is24Hour?: boolean;
58+
/**
59+
* The interval at which minutes can be selected. Possible values are: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 (iOS only)
60+
*/
61+
minuteInterval?: number;
62+
/**
63+
* Allows changing of the timeZone of the date picker. By default it uses the device's time zone (iOS only)
64+
*/
65+
timeZoneOffsetInMinutes?: number;
66+
/**
67+
* Props to pass the Dialog component
68+
*/
69+
dialogProps?: DialogProps;
70+
/**
71+
* style to apply to the iOS dialog header
72+
*/
73+
headerStyle?: StyleProp<ViewStyle>;
74+
/**
75+
* Render custom input
76+
*/
77+
renderInput?: () => React.ReactElement;
78+
/**
79+
* Override system theme variant (dark or light mode) used by the date picker.
80+
*/
81+
themeVariant?: 'light' | 'dark';
82+
/**
83+
* The component testID
84+
*/
85+
testID?: string;
86+
}
87+
interface DateTimePickerState {
88+
showExpandableOverlay: boolean;
89+
prevValue?: Date;
90+
value?: Date;
91+
}
92+
declare type DateTimePickerPropsInternal = DateTimePickerProps & BaseComponentInjectedProps;
93+
declare class DateTimePicker extends Component<DateTimePickerPropsInternal, DateTimePickerState> {
94+
static displayName: string;
95+
static defaultProps: {
96+
mode: string;
97+
enableErrors: boolean;
98+
validateOnBlur: boolean;
99+
};
100+
chosenDate?: Date;
101+
constructor(props: DateTimePickerPropsInternal);
102+
static getDerivedStateFromProps(nextProps: DateTimePickerProps, prevState: DateTimePickerState): {
103+
prevValue: Date | undefined;
104+
value: Date | undefined;
105+
} | null;
106+
handleChange: (event: any, date: Date) => void;
107+
toggleExpandableOverlay: (callback?: (() => void) | undefined) => void;
108+
onToggleExpandableModal: (value: boolean) => void;
109+
onDonePressed: () => void;
110+
getStringValue: () => string | undefined;
111+
renderExpandableOverlay: () => JSX.Element;
112+
renderHeader(): JSX.Element;
113+
renderDateTimePicker(): JSX.Element | null | undefined;
114+
renderExpandable: () => JSX.Element | null | undefined;
115+
render(): JSX.Element;
116+
}
117+
export { DateTimePicker };
118+
declare const _default: React.ComponentClass<DateTimePickerProps & {
119+
useCustomTheme?: boolean | undefined;
120+
}, any>;
121+
export default _default;

generatedTypes/src/components/dialog/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export interface DialogProps extends AlignmentModifiers, RNPartialProps {
2828
/**
2929
* The dialog height (default: undefined)
3030
*/
31-
height?: string | number;
31+
height?: string | number | null;
3232
/**
3333
* The direction of the allowed pan (default is DOWN).
3434
* Types: UP, DOWN, LEFT and RIGHT (using PanningProvider.Directions.###).
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/// <reference types="react" />
2+
import BaseInput from '../baseInput';
3+
/**
4+
* @description: A wrapper for TextInput component with extra functionality like floating placeholder and validations (This is an uncontrolled component)
5+
* @modifiers: Typography
6+
* @extends: TextInput
7+
* @extendsLink: https://reactnative.dev/docs/textinput
8+
* @gif: https://media.giphy.com/media/xULW8su8Cs5Z9Fq4PS/giphy.gif, https://media.giphy.com/media/3ohc1dhDcLS9FvWLJu/giphy.gif, https://media.giphy.com/media/oNUSOxnHdMP5ZnKYsh/giphy.gif
9+
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/TextFieldScreen/BasicTextFieldScreen.js
10+
*/
11+
export default class TextField extends BaseInput {
12+
static displayName: string;
13+
static propTypes: any;
14+
static defaultProps: {
15+
enableErrors: boolean;
16+
validateOnBlur: boolean;
17+
};
18+
constructor(props: any);
19+
UNSAFE_componentWillReceiveProps(nextProps: any): void;
20+
componentDidUpdate(_prevProps: any, prevState: any): void;
21+
onPlaceholderLayout: (event: any) => void;
22+
/** Actions */
23+
generatePropsWarnings(props: any): void;
24+
generateStyles(): void;
25+
getAccessibilityInfo(): {
26+
accessibilityLabel: any;
27+
accessibilityState: {
28+
disabled: boolean;
29+
} | undefined;
30+
};
31+
toggleExpandableModal: (value: any) => void;
32+
updateFloatingPlaceholderState: (withoutAnimation: any) => void;
33+
getPlaceholderText: (this: any, placeholder: any, helperText: any) => any;
34+
getStateColor(colorProp?: {}): any;
35+
getCharCount(): any;
36+
setCharCountColor(key: any): void;
37+
getCharCountColor(): any;
38+
getTopPaddings(): 25 | undefined;
39+
getTopErrorsPosition(): {
40+
top: number;
41+
} | undefined;
42+
isDisabled(): boolean;
43+
isCounterLimit(): boolean;
44+
hasText(value: any): boolean;
45+
shouldShowHelperText(): any;
46+
shouldFloatOnFocus(): any;
47+
shouldFloatPlaceholder(text: any): any;
48+
shouldFakePlaceholder(): boolean;
49+
shouldShowError(): any;
50+
getErrorMessage(): any;
51+
shouldShowTopError(): any;
52+
shouldDisplayRightButton(): any;
53+
shouldRenderTitle(): any;
54+
onPressRightButton: () => void;
55+
/** Renders */
56+
renderPlaceholder(): JSX.Element | undefined;
57+
renderPrefix(): JSX.Element | undefined;
58+
renderTitle(): JSX.Element | undefined;
59+
renderCharCounter(): JSX.Element | undefined;
60+
renderError(visible: any): JSX.Element | undefined;
61+
renderExpandableModal(): any;
62+
renderExpandableInput(): any;
63+
renderTextInput(): JSX.Element;
64+
renderRightButton(): JSX.Element | undefined;
65+
renderRightIcon(): JSX.Element | undefined;
66+
render(): JSX.Element;
67+
/** Events */
68+
onDoneEditingExpandableInput: () => void;
69+
onKeyPress: (event: any) => void;
70+
onChangeText: (text: any) => void;
71+
}

src/components/baseInput/Validators.js

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import _ from 'lodash';
2+
import {EmailValidator} from 'commons-validator-js';
3+
4+
const urlRegEx =
5+
/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i; //eslint-disable-line
6+
const decimalNumberRegEx = /^-?\d+[.,]?\d+$/;
7+
const integerRegEx = /^-?\d*$/; // allows empty string
8+
const priceRegEx = /^[0-9]{1,9}([.][0-9]{1,2})?$/;
9+
10+
const validators = {
11+
required: (value: string) => !_.isEmpty(value),
12+
email: (value: string) => new EmailValidator().isValid(value),
13+
url: (value: string) => urlRegEx.test(value),
14+
number: (value: string) => integerRegEx.test(value) || decimalNumberRegEx.test(value),
15+
price: (value: string) => priceRegEx.test(value)
16+
};
17+
18+
export default validators;

src/components/baseInput/index.js renamed to src/components/baseInput/index.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// @ts-nocheck
12
import _ from 'lodash';
23
import PropTypes from 'prop-types';
34
import 'react';
@@ -101,11 +102,11 @@ export default class BaseInput extends BaseComponent {
101102
}
102103
};
103104

104-
onChange = (event) => {
105+
onChange = event => {
105106
_.invoke(this.props, 'onChange', event);
106107
};
107108

108-
onChangeText = (text) => {
109+
onChangeText = text => {
109110
_.invoke(this.props, 'onChangeText', text);
110111
this.setState({value: text});
111112

@@ -147,8 +148,7 @@ export default class BaseInput extends BaseComponent {
147148
if (!validate) {
148149
return;
149150
}
150-
151-
151+
152152
let isValid = true;
153153
const inputValidators = _.isArray(validate) ? validate : [validate];
154154
let failingValidatorIndex;
@@ -205,7 +205,7 @@ export default class BaseInput extends BaseComponent {
205205

206206
getRequiredPlaceholder(placeholder) {
207207
const {markRequired} = this.getThemeProps();
208-
const shouldDisplayPlaceholderAsRequired = (this.isRequiredField() && markRequired && placeholder);
208+
const shouldDisplayPlaceholderAsRequired = this.isRequiredField() && markRequired && placeholder;
209209

210210
if (shouldDisplayPlaceholderAsRequired) {
211211
return `${placeholder} *`;
@@ -220,15 +220,16 @@ export default class BaseInput extends BaseComponent {
220220
return propsError || stateError;
221221
}
222222

223-
getColor(value) {
223+
getColor(value: string) {
224224
if (this.state.focused) {
225225
return Colors.grey10;
226226
} else {
227227
return _.isEmpty(value) ? Colors.grey40 : Colors.grey10;
228228
}
229229
}
230230

231-
toggleExpandableModal(...args) {
231+
toggleExpandableModal(...args: any[]) {
232+
// @ts-expect-error
232233
return this.input.toggleExpandableModal(...args);
233234
}
234235
}

0 commit comments

Comments
 (0)