@widergy/mobile-ui 2.16.0 → 2.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,108 @@
1
+ import React from 'react';
2
+ import { Pressable, View } from 'react-native';
3
+ import { array, bool, func, object, string } from 'prop-types';
4
+
5
+ import UTBaseInputField from '../UTBaseInputField';
6
+ import UTBottomSheet from '../UTBottomSheet';
7
+ import UTFieldLabel from '../UTFieldLabel';
8
+ import UTLabel from '../UTLabel';
9
+ import UTValidation from '../UTValidation';
10
+ import { TEST_IDS } from '../../constants/testIds';
11
+
12
+ import Calendar from './components/Calendar';
13
+ import { VARIANTS } from './constants';
14
+ import styles from './styles';
15
+
16
+ const { UTDatePicker: datePickerTestIds } = TEST_IDS;
17
+
18
+ const UTDatePickerLayout = ({
19
+ disabled,
20
+ displayPlaceholder,
21
+ displayValue,
22
+ errorMessage,
23
+ handleClose,
24
+ handleDaySelect,
25
+ hasError,
26
+ helpText,
27
+ inputStyle,
28
+ isOpen,
29
+ maxDate,
30
+ minDate,
31
+ modalProps,
32
+ onPress,
33
+ pickedDate,
34
+ readOnly,
35
+ required,
36
+ rightAdornments,
37
+ style,
38
+ title,
39
+ variant
40
+ }) => (
41
+ <View style={[styles.root, style?.root]} testID={datePickerTestIds.root}>
42
+ {!!title && <UTFieldLabel required={required}>{title}</UTFieldLabel>}
43
+
44
+ <Pressable onPress={onPress} style={styles.pressable}>
45
+ <UTBaseInputField
46
+ alwaysShowPlaceholder
47
+ dataTestId={datePickerTestIds.input}
48
+ disabled={disabled}
49
+ editable={false}
50
+ error={hasError}
51
+ placeholder={displayPlaceholder}
52
+ readOnly={readOnly}
53
+ rightAdornments={rightAdornments}
54
+ style={inputStyle}
55
+ value={displayValue}
56
+ />
57
+ </Pressable>
58
+
59
+ {!!helpText && (
60
+ <UTLabel colorTheme="gray" variant="small">
61
+ {helpText}
62
+ </UTLabel>
63
+ )}
64
+
65
+ {variant === VARIANTS.select && !!errorMessage && (
66
+ <UTValidation
67
+ dataTestId={datePickerTestIds.errorMessage}
68
+ validationData={[{ items: [{ status: 'error', text: errorMessage }] }]}
69
+ />
70
+ )}
71
+
72
+ <UTBottomSheet
73
+ adjustableHeight
74
+ onClose={handleClose}
75
+ visible={isOpen}
76
+ withBodyPadding={false}
77
+ {...modalProps}
78
+ >
79
+ <Calendar maxDate={maxDate} minDate={minDate} onDaySelect={handleDaySelect} pickedDate={pickedDate} />
80
+ </UTBottomSheet>
81
+ </View>
82
+ );
83
+
84
+ UTDatePickerLayout.propTypes = {
85
+ disabled: bool,
86
+ displayPlaceholder: string,
87
+ displayValue: string,
88
+ errorMessage: string,
89
+ handleClose: func,
90
+ handleDaySelect: func,
91
+ hasError: bool,
92
+ helpText: string,
93
+ inputStyle: object,
94
+ isOpen: bool,
95
+ maxDate: string,
96
+ minDate: string,
97
+ modalProps: object,
98
+ onPress: func,
99
+ pickedDate: object,
100
+ readOnly: bool,
101
+ required: bool,
102
+ rightAdornments: array,
103
+ style: object,
104
+ title: string,
105
+ variant: string
106
+ };
107
+
108
+ export default UTDatePickerLayout;
@@ -0,0 +1,20 @@
1
+ import { bool, elementType, func, object, oneOf, shape, string } from 'prop-types';
2
+
3
+ export const propTypes = {
4
+ clearable: bool,
5
+ CustomIcon: elementType,
6
+ disabled: bool,
7
+ error: string,
8
+ helpText: string,
9
+ modalProps: object,
10
+ onChange: func,
11
+ placeholder: string,
12
+ range: shape({ maxDate: string, minDate: string }),
13
+ readOnly: bool,
14
+ required: bool,
15
+ size: oneOf(['sm', 'md']),
16
+ style: shape({ root: object }),
17
+ title: string,
18
+ value: string,
19
+ variant: oneOf(['select', 'picker'])
20
+ };
@@ -0,0 +1,63 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ const styles = StyleSheet.create({
4
+ calendarRoot: {
5
+ paddingHorizontal: 24,
6
+ paddingTop: 16
7
+ },
8
+ dayCell: {
9
+ flex: 1,
10
+ paddingVertical: 2,
11
+ textAlign: 'center'
12
+ },
13
+ month: {
14
+ gap: 2,
15
+ minHeight: 260
16
+ },
17
+ nav: {
18
+ alignItems: 'center',
19
+ flexDirection: 'row',
20
+ justifyContent: 'space-between',
21
+ marginBottom: 24
22
+ },
23
+ navLabel: {
24
+ flex: 1,
25
+ textAlign: 'center'
26
+ },
27
+ navSpacer: {
28
+ width: 36
29
+ },
30
+ pickerColumn: {
31
+ flex: 1,
32
+ overflow: 'hidden'
33
+ },
34
+ pickerContainer: {
35
+ flexDirection: 'row',
36
+ gap: 8,
37
+ height: 260
38
+ },
39
+ pickerScroll: {
40
+ height: 260
41
+ },
42
+ pickerScrollContent: {
43
+ paddingBottom: 220
44
+ },
45
+ pressable: {
46
+ width: '100%'
47
+ },
48
+ root: {
49
+ gap: 8
50
+ },
51
+ week: {
52
+ flexDirection: 'row'
53
+ },
54
+ yearItem: {
55
+ alignItems: 'center',
56
+ borderRadius: 8,
57
+ height: 40,
58
+ justifyContent: 'center',
59
+ width: '100%'
60
+ }
61
+ });
62
+
63
+ export default styles;
@@ -0,0 +1,18 @@
1
+ export const getDayCellButtonStyle = (selected, theme) => ({
2
+ root: {
3
+ alignItems: 'center',
4
+ flex: 1,
5
+ height: 36,
6
+ justifyContent: 'center',
7
+ paddingHorizontal: 0,
8
+ paddingVertical: 0,
9
+ ...(selected && {
10
+ backgroundColor: theme.Palette.accent['04'],
11
+ borderRadius: 18
12
+ })
13
+ }
14
+ });
15
+
16
+ export const getYearItemStyle = (selected, theme) => ({
17
+ backgroundColor: selected ? theme.Palette.accent['04'] : undefined
18
+ });
@@ -0,0 +1,52 @@
1
+ import dayjs from 'dayjs';
2
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
3
+
4
+ import { DAY_UNIT, MONTH_UNIT, OUTPUT_LABEL_MASK, YEAR_RANGE_AFTER, YEAR_RANGE_BEFORE } from './constants';
5
+
6
+ dayjs.extend(customParseFormat);
7
+
8
+ export const isSelected = (date, selectedDate) => selectedDate && date.isSame(selectedDate, DAY_UNIT);
9
+
10
+ export const dateMatchesFormat = (date, targetFormat) => dayjs(date, targetFormat, true).isValid();
11
+
12
+ export const getFinalDate = ({ date, maxDate, minDate }) => {
13
+ const formattedDate = dayjs(date);
14
+ if (maxDate && formattedDate?.isAfter(dayjs(maxDate, OUTPUT_LABEL_MASK)))
15
+ return dayjs(maxDate, OUTPUT_LABEL_MASK);
16
+ if (minDate && formattedDate?.isBefore(dayjs(minDate, OUTPUT_LABEL_MASK)))
17
+ return dayjs(minDate, OUTPUT_LABEL_MASK);
18
+ return formattedDate;
19
+ };
20
+
21
+ export const getWeeks = month => {
22
+ const firstDay = month.startOf(MONTH_UNIT);
23
+ const lastDay = month.endOf(MONTH_UNIT);
24
+ const startDate = firstDay.subtract(firstDay.day(), DAY_UNIT);
25
+
26
+ const weeks = [];
27
+ let current = startDate;
28
+
29
+ do {
30
+ const weekStart = current;
31
+ weeks.push(Array.from({ length: 7 }, (_, i) => weekStart.add(i, DAY_UNIT)));
32
+ current = current.add(7, DAY_UNIT);
33
+ } while (current.isBefore(lastDay) || current.isSame(lastDay, DAY_UNIT));
34
+
35
+ return weeks;
36
+ };
37
+
38
+ export const getYearRange = (minDateStr, maxDateStr) => {
39
+ const currentYear = dayjs().year();
40
+ const minYear = minDateStr ? dayjs(minDateStr, OUTPUT_LABEL_MASK).year() : currentYear - YEAR_RANGE_BEFORE;
41
+ const maxYear = maxDateStr ? dayjs(maxDateStr, OUTPUT_LABEL_MASK).year() : currentYear + YEAR_RANGE_AFTER;
42
+ const years = [];
43
+ for (let y = maxYear; y >= minYear; y--) years.push(y);
44
+ return years;
45
+ };
46
+
47
+ export const autoFormatDate = val => {
48
+ const digits = val.replace(/\D/g, '').slice(0, 8);
49
+ if (digits.length <= 2) return digits;
50
+ if (digits.length <= 4) return `${digits.slice(0, 2)}/${digits.slice(2)}`;
51
+ return `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`;
52
+ };
@@ -44,6 +44,19 @@ export const TEST_ID_CONSTANTS = {
44
44
 
45
45
  export const TEST_IDS = {
46
46
  modal: 'modal',
47
+ UTDatePicker: {
48
+ calendar: 'UTDatePicker.calendar',
49
+ calendarMonthYear: 'UTDatePicker.calendar.monthYear',
50
+ calendarNextBtn: 'UTDatePicker.calendar.nextBtn',
51
+ calendarPrevBtn: 'UTDatePicker.calendar.prevBtn',
52
+ errorMessage: 'UTDatePicker.errorMessage',
53
+ input: 'UTDatePicker.input',
54
+ monthItem: 'UTDatePicker.monthItem',
55
+ monthView: 'UTDatePicker.monthView',
56
+ root: 'UTDatePicker.root',
57
+ yearItem: 'UTDatePicker.yearItem',
58
+ yearView: 'UTDatePicker.yearView'
59
+ },
47
60
  roundView: 'roundView',
48
61
  skeletonLoader: 'skeletonLoader',
49
62
  topbar: {
package/lib/index.js CHANGED
@@ -49,6 +49,7 @@ export { default as UTCuit } from './components/UTCuit';
49
49
  export { default as UTCheckList } from './components/UTCheckList';
50
50
  export { default as UTDataCategory } from './components/UTDataCategory';
51
51
  export { default as UTDataElement } from './components/UTDataElement';
52
+ export { default as UTDatePicker } from './components/UTDatePicker';
52
53
  export { default as UTDetailDrawer } from './components/UTDetailDrawer';
53
54
  export { default as UTIcon } from './components/UTIcon';
54
55
  export { default as UTImage } from './components/UTImage';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@widergy/mobile-ui",
3
3
  "description": "Widergy Mobile Components",
4
4
  "author": "widergy",
5
- "version": "2.16.0",
5
+ "version": "2.17.1",
6
6
  "repository": "https://github.com/widergy/mobile-ui.git",
7
7
  "main": "lib/index.js",
8
8
  "files": [
@@ -43,6 +43,7 @@
43
43
  "@tabler/icons-react-native": "^3.34.1",
44
44
  "@widergy/web-utils": "^2.0.0",
45
45
  "core-js": "3",
46
+ "dayjs": "^1.11.10",
46
47
  "deprecated-react-native-prop-types": "^5.0.0",
47
48
  "expo-document-picker": "^13.1.6",
48
49
  "expo-image-manipulator": "^13.1.7",
@@ -73,12 +74,12 @@
73
74
  "@commitlint/config-conventional": "^17.7.0",
74
75
  "@eslint/compat": "^1.4.0",
75
76
  "@eslint/eslintrc": "^3.3.0",
76
- "@widergy/semantic-release-package-config": "^1.0.0",
77
- "@widergy/eslint-config": "^1.0.0",
78
77
  "@react-native/babel-preset": "0.73.0",
78
+ "@widergy/eslint-config": "^1.0.0",
79
+ "@widergy/semantic-release-package-config": "^1.0.0",
80
+ "babel-jest": "^29.6.2",
79
81
  "babel-plugin-import-glob": "^2.0.0",
80
82
  "babel-plugin-module-resolver": "^5.0.0",
81
- "babel-jest": "^29.6.2",
82
83
  "babel-preset-minify": "^0.5.2",
83
84
  "eslint": "^9.38.0",
84
85
  "eslint-config-airbnb": "^19.0.4",