@tecsinapse/react-core 1.12.8 → 1.14.0

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.
Files changed (101) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/components/atoms/Input/InputElement/InputElement.d.ts +5 -3
  3. package/dist/components/atoms/Input/InputElement/InputElement.js +22 -8
  4. package/dist/components/atoms/Input/InputElement/InputElement.js.map +1 -1
  5. package/dist/components/atoms/Input/hooks/useNumberMask.d.ts +8 -0
  6. package/dist/components/atoms/Input/hooks/useNumberMask.js +98 -0
  7. package/dist/components/atoms/Input/hooks/useNumberMask.js.map +1 -0
  8. package/dist/components/atoms/Input/hooks/useStringMask.d.ts +8 -0
  9. package/dist/components/atoms/Input/hooks/useStringMask.js +109 -0
  10. package/dist/components/atoms/Input/hooks/useStringMask.js.map +1 -0
  11. package/dist/components/atoms/Input/index.d.ts +2 -3
  12. package/dist/components/atoms/Input/index.js +12 -26
  13. package/dist/components/atoms/Input/index.js.map +1 -1
  14. package/dist/components/atoms/ProgressBar/ProgressBar.d.ts +1 -1
  15. package/dist/components/atoms/ProgressBar/ProgressBar.js +6 -6
  16. package/dist/components/atoms/ProgressBar/ProgressBar.js.map +1 -1
  17. package/dist/components/molecules/Calendar/components/MonthWeek.js +5 -10
  18. package/dist/components/molecules/Calendar/components/MonthWeek.js.map +1 -1
  19. package/dist/components/molecules/Calendar/index.d.ts +1 -1
  20. package/dist/components/molecules/Calendar/index.js +6 -0
  21. package/dist/components/molecules/Calendar/index.js.map +1 -1
  22. package/dist/components/molecules/Calendar/styled.js +0 -17
  23. package/dist/components/molecules/Calendar/styled.js.map +1 -1
  24. package/dist/components/molecules/DatePicker/DatePicker.d.ts +6 -5
  25. package/dist/components/molecules/DatePicker/DatePicker.js +22 -32
  26. package/dist/components/molecules/DatePicker/DatePicker.js.map +1 -1
  27. package/dist/components/molecules/DatePicker/styled.d.ts +0 -14
  28. package/dist/components/molecules/DatePicker/styled.js +1 -46
  29. package/dist/components/molecules/DatePicker/styled.js.map +1 -1
  30. package/dist/components/molecules/DateTimePicker/DateTimePicker.d.ts +5 -4
  31. package/dist/components/molecules/DateTimePicker/DateTimePicker.js +35 -37
  32. package/dist/components/molecules/DateTimePicker/DateTimePicker.js.map +1 -1
  33. package/dist/components/molecules/DateTimePicker/styled.d.ts +0 -21
  34. package/dist/components/molecules/DateTimePicker/styled.js +3 -51
  35. package/dist/components/molecules/DateTimePicker/styled.js.map +1 -1
  36. package/dist/components/molecules/Grid/Item/Item.d.ts +1 -1
  37. package/dist/components/molecules/Grid/Item/Item.js +7 -5
  38. package/dist/components/molecules/Grid/Item/Item.js.map +1 -1
  39. package/dist/components/molecules/HintInputContainer/HintInputContainer.d.ts +3 -2
  40. package/dist/components/molecules/HintInputContainer/HintInputContainer.js +4 -4
  41. package/dist/components/molecules/HintInputContainer/HintInputContainer.js.map +1 -1
  42. package/dist/components/molecules/TextArea/TextArea.d.ts +3 -1
  43. package/dist/components/molecules/TextArea/TextArea.js +4 -4
  44. package/dist/components/molecules/TextArea/TextArea.js.map +1 -1
  45. package/dist/index.d.ts +2 -2
  46. package/dist/index.js +15 -29
  47. package/dist/index.js.map +1 -1
  48. package/dist/utils/ResponsiveFontSize.js +1 -1
  49. package/dist/utils/ResponsiveFontSize.js.map +1 -1
  50. package/dist/utils/formatWithMask.d.ts +3 -0
  51. package/dist/utils/formatWithMask.js +31 -0
  52. package/dist/utils/formatWithMask.js.map +1 -0
  53. package/dist/utils/index.d.ts +2 -0
  54. package/dist/utils/index.js +28 -0
  55. package/dist/utils/index.js.map +1 -1
  56. package/dist/utils/masks.d.ts +10 -0
  57. package/dist/utils/masks.js +18 -0
  58. package/dist/utils/masks.js.map +1 -0
  59. package/package.json +2 -2
  60. package/src/components/atoms/Input/InputElement/InputElement.tsx +37 -11
  61. package/src/components/atoms/Input/hooks/useNumberMask.ts +99 -0
  62. package/src/components/atoms/Input/hooks/useStringMask.ts +126 -0
  63. package/src/components/atoms/Input/index.ts +2 -3
  64. package/src/components/atoms/ProgressBar/ProgressBar.tsx +5 -5
  65. package/src/components/molecules/Calendar/components/MonthWeek.tsx +5 -10
  66. package/src/components/molecules/Calendar/index.ts +1 -0
  67. package/src/components/molecules/Calendar/styled.ts +0 -22
  68. package/src/components/molecules/DatePicker/DatePicker.tsx +32 -41
  69. package/src/components/molecules/DatePicker/styled.ts +0 -40
  70. package/src/components/molecules/DateTimePicker/DateTimePicker.tsx +46 -52
  71. package/src/components/molecules/DateTimePicker/styled.ts +1 -49
  72. package/src/components/molecules/Grid/Item/Item.tsx +3 -5
  73. package/src/components/molecules/HintInputContainer/HintInputContainer.tsx +3 -8
  74. package/src/components/molecules/TextArea/TextArea.tsx +3 -9
  75. package/src/index.ts +3 -5
  76. package/src/utils/ResponsiveFontSize.ts +2 -2
  77. package/src/utils/formatWithMask.ts +25 -0
  78. package/src/utils/index.ts +4 -2
  79. package/src/utils/masks.ts +13 -0
  80. package/dist/components/atoms/Input/hooks/useCurrencyMask.d.ts +0 -3
  81. package/dist/components/atoms/Input/hooks/useCurrencyMask.js +0 -69
  82. package/dist/components/atoms/Input/hooks/useCurrencyMask.js.map +0 -1
  83. package/dist/components/atoms/Input/hooks/useMask.d.ts +0 -9
  84. package/dist/components/atoms/Input/hooks/useMask.js +0 -61
  85. package/dist/components/atoms/Input/hooks/useMask.js.map +0 -1
  86. package/dist/components/atoms/Input/masks/index.d.ts +0 -10
  87. package/dist/components/atoms/Input/masks/index.js +0 -18
  88. package/dist/components/atoms/Input/masks/index.js.map +0 -1
  89. package/dist/components/molecules/DatePicker/Modal.d.ts +0 -8
  90. package/dist/components/molecules/DatePicker/Modal.js +0 -60
  91. package/dist/components/molecules/DatePicker/Modal.js.map +0 -1
  92. package/dist/components/molecules/DateTimePicker/Modal.d.ts +0 -7
  93. package/dist/components/molecules/DateTimePicker/Modal.js +0 -89
  94. package/dist/components/molecules/DateTimePicker/Modal.js.map +0 -1
  95. package/src/components/atoms/Input/hooks/useCurrencyMask.ts +0 -74
  96. package/src/components/atoms/Input/hooks/useMask.ts +0 -92
  97. package/src/components/atoms/Input/masks/index.ts +0 -12
  98. package/src/components/molecules/DatePicker/DatePicker.stories.tsx +0 -44
  99. package/src/components/molecules/DatePicker/Modal.tsx +0 -51
  100. package/src/components/molecules/DateTimePicker/DateTimePicker.stories.tsx +0 -26
  101. package/src/components/molecules/DateTimePicker/Modal.tsx +0 -84
@@ -1,20 +1,27 @@
1
1
  import { useTheme } from '@emotion/react';
2
2
  import { ThemeProp } from '@tecsinapse/react-core';
3
- import React, { FC } from 'react';
3
+ import React, { FC, useEffect, useState } from 'react';
4
4
  import { StyleProp, TextInputProps, TextStyle } from 'react-native';
5
- import { IMask } from '../hooks/useMask';
6
5
  import { StyledInputElement } from '../styled';
6
+ import { MaskType, useStringMask } from '../hooks/useStringMask';
7
+ import { CurrencyOptions, useNumberMask } from '../hooks/useNumberMask';
7
8
 
8
9
  export interface InputElementProps
9
10
  extends Omit<TextInputProps, 'onChange' | 'value' | 'ref'> {
10
11
  style?: StyleProp<TextStyle>;
11
- /**
12
- * TODO:
13
- */
14
- value?: string | IMask;
12
+ value: string | number;
15
13
  placeholder?: string;
16
14
  disabled?: boolean;
17
- onChange?: (value: string) => void;
15
+ onChange?: (value: any) => void;
16
+ /**
17
+ To use mask for strings you have to pass a MaskType[] or ((value: string) => MaskType[])
18
+ A MaskType can be a string, RegExp, or Array<RegExp>.
19
+ In case we have a string, '9' represents digits, 'a' represents alphabet characters, and any other character represents fixed characters in the mask.
20
+ For example a phone mask can be represented as ['(99) \\99999-9999'], or ['(99) ', '/[9]/', '9999-9999'], or ['(', /[0-9]/, /[0-9]/, ') ', '/[9]/', '9999-9999'] and many others.
21
+ To use mask for numbers you have to pass a CurrencyOptions object
22
+ A CurrencyOptions object contains symbol, separator, decimal, precision. For example {symbol: 'R$ ', separator: '.', decimal: ',', precision: 2,}.
23
+ **/
24
+ mask?: (MaskType[] | ((value: string) => MaskType[])) | CurrencyOptions;
18
25
  onFocus?: () => void;
19
26
  onBlur?: () => void;
20
27
  ref?: React.Ref<any>;
@@ -28,21 +35,40 @@ const InputElement: FC<InputElementProps> = React.forwardRef(
28
35
  value,
29
36
  disabled = false,
30
37
  placeholderTextColor,
38
+ mask,
31
39
  ...rest
32
40
  },
33
41
  ref: React.Ref<any>
34
42
  ): JSX.Element => {
35
43
  const theme = useTheme() as ThemeProp;
36
- const _value =
37
- typeof value === 'string' ? value : value?.maskValue?.formatted;
38
44
  const _placeholderColor = placeholderTextColor || theme.font.color.dark;
39
45
 
46
+ const [maskValue, setMaskValue] =
47
+ mask === undefined
48
+ ? useState<string>(String(value))
49
+ : Array.isArray(mask) || typeof mask === 'function'
50
+ ? useStringMask(mask, String(value))
51
+ : useNumberMask(mask, value);
52
+
53
+ useEffect(() => {
54
+ if (onChange) {
55
+ if (typeof maskValue === 'string') onChange(maskValue);
56
+ else onChange(maskValue?.raw);
57
+ }
58
+ }, [maskValue]);
59
+
60
+ const onChangeValue = (value: string) => {
61
+ setMaskValue(value);
62
+ };
63
+
40
64
  return (
41
65
  <StyledInputElement
42
66
  {...rest}
43
67
  ref={ref}
44
- onChangeText={onChange}
45
- value={_value}
68
+ onChangeText={onChangeValue}
69
+ value={
70
+ typeof maskValue === 'string' ? maskValue : maskValue?.formatted ?? ''
71
+ }
46
72
  placeholder={placeholder}
47
73
  placeholderTextColor={_placeholderColor}
48
74
  disabled={disabled}
@@ -0,0 +1,99 @@
1
+ import currency from 'currency.js';
2
+ import { useCallback, useState } from 'react';
3
+ import { extractNumbersFromString } from '../../../../utils';
4
+ import { MaskValue } from './useStringMask';
5
+
6
+ export type CurrencyOptions = currency.Options;
7
+
8
+ const DEFAULT_OPTIONS: CurrencyOptions = {
9
+ symbol: 'R$ ',
10
+ separator: '.',
11
+ decimal: ',',
12
+ precision: 2,
13
+ };
14
+
15
+ const getRegex = (precision: number) =>
16
+ new RegExp(`\\B(?=(\\d{${precision}})(?!\\d))`, 'g');
17
+
18
+ export const getInternalNumberAndMask = (
19
+ value: string | number,
20
+ options?: CurrencyOptions
21
+ ): { internalNumber: number; mergedOptions: CurrencyOptions } => {
22
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
23
+ const { precision = -1 } = mergedOptions;
24
+
25
+ let internalNumber;
26
+
27
+ if (typeof value === 'number') {
28
+ if (precision) {
29
+ let stringValue = String(value);
30
+ const decimalIndex = stringValue.indexOf('.');
31
+ const currentPrecision = decimalIndex + precision;
32
+ if (decimalIndex !== -1 && currentPrecision <= stringValue.length) {
33
+ const zeros = stringValue.length + 1 - currentPrecision;
34
+ for (let i = 0; i < zeros; i++) stringValue = stringValue + `0`;
35
+ }
36
+ internalNumber = Number(stringValue);
37
+ } else {
38
+ internalNumber = value;
39
+ }
40
+ } else {
41
+ const onlyNumbers = String(extractNumbersFromString(value));
42
+ const padZeros = String(onlyNumbers).padStart(precision + 1, '0');
43
+ internalNumber = Number(padZeros.replace(getRegex(precision), '.'));
44
+ }
45
+
46
+ if (internalNumber > Number.MAX_SAFE_INTEGER) {
47
+ internalNumber = Number.MAX_SAFE_INTEGER;
48
+ }
49
+
50
+ if (internalNumber < Number.MIN_SAFE_INTEGER) {
51
+ internalNumber = Number.MIN_SAFE_INTEGER;
52
+ }
53
+
54
+ return {
55
+ internalNumber,
56
+ mergedOptions,
57
+ };
58
+ };
59
+
60
+ /**
61
+ * TODO:
62
+ * @param options
63
+ * @param defaultValue
64
+ * @returns
65
+ */
66
+ export const useNumberMask = (
67
+ options?: CurrencyOptions,
68
+ defaultValue?: string | number
69
+ ): [MaskValue, (value: string) => void] => {
70
+ const applyMask = useCallback(
71
+ (value: string | number = 0): MaskValue => {
72
+ const { internalNumber, mergedOptions } = getInternalNumberAndMask(
73
+ value,
74
+ options
75
+ );
76
+
77
+ return {
78
+ raw: internalNumber,
79
+ formatted: currency(internalNumber).format(mergedOptions),
80
+ };
81
+ },
82
+ [options, getRegex]
83
+ );
84
+
85
+ const [value, setValue] = useState<MaskValue>(applyMask(defaultValue));
86
+
87
+ const handleChangeValue = useCallback(
88
+ (formattedValue: string) => {
89
+ const { raw, formatted } = applyMask(formattedValue);
90
+ setValue({
91
+ raw,
92
+ formatted,
93
+ });
94
+ },
95
+ [applyMask, setValue]
96
+ );
97
+
98
+ return [value, handleChangeValue];
99
+ };
@@ -0,0 +1,126 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ export interface MaskValue {
4
+ formatted?: string;
5
+ raw?: any;
6
+ }
7
+
8
+ export type MaskType = string | RegExp | Array<RegExp>;
9
+
10
+ /**
11
+ * TODO:
12
+ * @param value
13
+ * @param mask
14
+ * @returns
15
+ */
16
+ export const mergeMask = (value = '', mask: MaskType[]): MaskValue => {
17
+ let formatted = '';
18
+ let raw = '';
19
+ let iMask = 0;
20
+ let iChars = 0;
21
+
22
+ while (!(iMask === mask.length || iChars === value.length)) {
23
+ const maskChar = mask[iMask];
24
+ const valueChar = value[iChars];
25
+
26
+ if (maskChar === valueChar) {
27
+ formatted += maskChar;
28
+ iChars++;
29
+ iMask++;
30
+ continue;
31
+ }
32
+
33
+ const rawValueChar = value[iChars];
34
+
35
+ if (typeof maskChar === 'object') {
36
+ iChars++;
37
+
38
+ const maskCharRegex = Array.isArray(maskChar) ? maskChar[0] : maskChar;
39
+ const matchRegex = RegExp(maskCharRegex).test(valueChar);
40
+
41
+ if (matchRegex) {
42
+ formatted += valueChar;
43
+ raw += rawValueChar;
44
+ iMask++;
45
+ }
46
+ } else {
47
+ formatted += maskChar;
48
+ iMask++;
49
+ }
50
+ }
51
+
52
+ return { raw, formatted };
53
+ };
54
+
55
+ export const getMask = (
56
+ mask: MaskType[] | ((value: string) => MaskType[]),
57
+ newValue: string
58
+ ): MaskType[] => {
59
+ let maskArray: MaskType[];
60
+ const regexArray: MaskType[] = [];
61
+
62
+ if (typeof mask === 'function') {
63
+ maskArray = mask(newValue);
64
+ } else {
65
+ maskArray = mask;
66
+ }
67
+
68
+ maskArray.forEach(exp => {
69
+ if (typeof exp !== 'string') {
70
+ if (Array.isArray(exp)) regexArray.push(exp);
71
+ else regexArray.push(exp);
72
+ } else {
73
+ for (let i = 0; i < exp.length; i++) {
74
+ if (exp[i] === '\\') {
75
+ regexArray.push(exp[i + 1]);
76
+ i++;
77
+ } else {
78
+ if (exp[i] === '9') regexArray.push(/\d/);
79
+ else if (exp[i] === 'a') regexArray.push(/[a-zA-Z]/);
80
+ else regexArray.push(exp[i]);
81
+ }
82
+ }
83
+ }
84
+ });
85
+
86
+ return regexArray;
87
+ };
88
+
89
+ /**
90
+ * TODO:
91
+ * @param mask
92
+ * @param defaultValue
93
+ * @returns
94
+ */
95
+ export const useStringMask = (
96
+ mask: MaskType[] | ((value: string) => MaskType[]),
97
+ defaultValue?: string
98
+ ): [MaskValue, (text: string) => void] => {
99
+ const applyMask = useCallback(
100
+ (value = ''): MaskValue => {
101
+ const selectedMask = getMask(mask, value);
102
+ const { formatted, raw } = mergeMask(value, selectedMask);
103
+
104
+ return {
105
+ raw,
106
+ formatted,
107
+ };
108
+ },
109
+ [mask]
110
+ );
111
+
112
+ const [value, setValue] = useState<MaskValue>(applyMask(defaultValue));
113
+
114
+ const handleChangeValue = useCallback(
115
+ (formattedValue: string) => {
116
+ const { raw, formatted } = applyMask(formattedValue);
117
+ setValue({
118
+ raw,
119
+ formatted,
120
+ });
121
+ },
122
+ [applyMask, setValue]
123
+ );
124
+
125
+ return [value, handleChangeValue];
126
+ };
@@ -1,7 +1,7 @@
1
1
  export { default as Hint } from './Hint';
2
- export * from './hooks/useCurrencyMask';
3
2
  export * from './hooks/useInputFocus';
4
- export * from './hooks/useMask';
3
+ export * from './hooks/useNumberMask';
4
+ export * from './hooks/useStringMask';
5
5
  export {
6
6
  default as InputContainer,
7
7
  InputContainerProps,
@@ -11,7 +11,6 @@ export {
11
11
  default as InputElement,
12
12
  InputElementProps,
13
13
  } from './InputElement/InputElement';
14
- export * from './masks';
15
14
  export {
16
15
  PressableInputContainer,
17
16
  PressableInputContainerProps,
@@ -1,13 +1,13 @@
1
+ import { useTheme } from '@emotion/react';
1
2
  import * as React from 'react';
2
3
  import { Animated, ViewProps } from 'react-native';
3
- import { Container, Progress, Segment } from './styled';
4
- import { useTheme } from '@emotion/react';
5
4
  import {
6
5
  ColorGradationType,
7
6
  ColorType,
8
- extractNumbersFromString,
9
- ThemeProp,
10
- } from '@tecsinapse/react-core';
7
+ ThemeProp
8
+ } from '../../../types/defaults';
9
+ import { extractNumbersFromString } from '../../../utils';
10
+ import { Container, Progress, Segment } from './styled';
11
11
 
12
12
  export interface ProgressBarProps extends ViewProps {
13
13
  /** Number of segments. Defaults to 1. Set to 1 when 0 or less */
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { compareAsc as compare, differenceInDays, isSameDay } from 'date-fns';
2
+ import { compareAsc as compare, isSameDay } from 'date-fns';
3
3
  import { Cell, Selected, Week } from '../styled';
4
4
  import { Value, DateRange, SelectionType } from '../Calendar';
5
5
  import { TextProps } from '@tecsinapse/react-core';
@@ -62,7 +62,7 @@ const MonthWeek = <T extends SelectionType>({
62
62
 
63
63
  if (!highest) {
64
64
  if (compare(date, lowest) === -1) {
65
- newValue = { lowest: date, highest: lowest };
65
+ newValue = { lowest: date, highest: undefined };
66
66
  } else if (compare(date, lowest) === 0) {
67
67
  newValue = undefined;
68
68
  } else {
@@ -70,17 +70,12 @@ const MonthWeek = <T extends SelectionType>({
70
70
  }
71
71
  } else {
72
72
  if (compare(date, lowest) === -1) {
73
- newValue = { lowest: date, highest: highest };
73
+ newValue = { lowest: date, highest: undefined };
74
74
  } else if (compare(date, lowest) === 0) {
75
- newValue = { lowest: highest, highest: undefined };
75
+ newValue = undefined;
76
76
  } else {
77
77
  if (compare(date, highest) === -1) {
78
- const lowestDiff = Math.abs(differenceInDays(date, lowest));
79
- const highestDiff = Math.abs(differenceInDays(date, highest));
80
- newValue = {
81
- lowest: lowestDiff < highestDiff ? date : lowest,
82
- highest: highestDiff <= lowestDiff ? date : highest,
83
- };
78
+ newValue = { lowest: lowest, highest: date };
84
79
  } else if (compare(date, highest) === 0) {
85
80
  newValue = { lowest: lowest, highest: undefined };
86
81
  } else {
@@ -3,4 +3,5 @@ export {
3
3
  CalendarProps,
4
4
  SelectionType,
5
5
  DateRange,
6
+ Value
6
7
  } from './Calendar';
@@ -19,26 +19,6 @@ export const TitleContainer = styled.View<Partial<StyleProps>>`
19
19
  background-color: ${({ theme }) => theme.color.secondary.xlight};
20
20
  `;
21
21
 
22
- const surfaceBorderRight = ({
23
- isRright,
24
- theme,
25
- }: ButtonBorders & Partial<StyleProps>) =>
26
- !isWeb &&
27
- isRright &&
28
- css`
29
- border-top-right-radius: ${theme?.borderRadius.deca};
30
- `;
31
-
32
- const surfaceBorderLeft = ({
33
- isLeft,
34
- theme,
35
- }: ButtonBorders & Partial<StyleProps>) =>
36
- !isWeb &&
37
- isLeft &&
38
- css`
39
- border-top-left-radius: ${theme?.borderRadius.deca};
40
- `;
41
-
42
22
  export const Control = styled(PressableSurface)(
43
23
  (
44
24
  props: Partial<StyleProps> & ButtonBorders & { align: 'start' | 'end' }
@@ -47,8 +27,6 @@ export const Control = styled(PressableSurface)(
47
27
  padding: ${props.theme?.spacing.centi};
48
28
  border-radius: ${props.theme?.borderRadius.mili};
49
29
  margin: ${props.theme?.spacing.mili};
50
- ${surfaceBorderRight(props)}
51
- ${surfaceBorderLeft(props)}
52
30
  `
53
31
  );
54
32
 
@@ -1,29 +1,27 @@
1
1
  import { format as formatDate } from 'date-fns';
2
2
  import * as React from 'react';
3
- import { ModalBaseProps } from 'react-native';
3
+ import { useEffect } from 'react';
4
4
  import { InputContainerProps, useInputFocus } from '../../atoms/Input';
5
5
  import { Text, TextProps } from '../../atoms/Text';
6
6
  import { CalendarProps, DateRange, SelectionType } from '../Calendar';
7
- import { DatePickerModalProps, Modal } from './Modal';
8
- import { CalendarIcon, getStyledTextComponent } from './styled';
9
7
  import { HintInputContainer } from '../HintInputContainer';
10
- import { useEffect } from 'react';
8
+ import { CalendarIcon, getStyledTextComponent } from './styled';
11
9
 
12
- export interface DatePickerProps<T extends SelectionType>
13
- extends InputContainerProps,
14
- DatePickerModalProps<T>,
15
- Omit<CalendarProps<T>, 'style'> {
10
+ export interface DatePickerProps<T extends SelectionType> extends InputContainerProps, Omit<CalendarProps<T>, 'style'> {
16
11
  controlComponent?: (
17
12
  onPress: () => void,
18
13
  displayValue?: string
19
14
  ) => JSX.Element;
20
15
  TextComponent?: React.FC<TextProps>;
21
- animationType?: ModalBaseProps['animationType'];
16
+ CalendarComponent: React.FC<CalendarProps<T>>
22
17
  placeholder?: string;
23
18
  onFocus?: () => void | never;
24
19
  onBlur?: () => void | never;
25
20
  format?: string;
26
21
  closeOnPick?: boolean;
22
+ renderCalendar: (calendar: React.ReactElement, blur?: () => void) => JSX.Element|null
23
+ requestShowCalendar: () => void
24
+ requestCloseCalendar: () => void
27
25
  }
28
26
 
29
27
  function DatePicker<T extends SelectionType>({
@@ -34,7 +32,6 @@ function DatePicker<T extends SelectionType>({
34
32
  value,
35
33
  type,
36
34
  format = 'yyyy-MM-dd',
37
-
38
35
  placeholder,
39
36
  onFocus,
40
37
  onBlur,
@@ -45,31 +42,26 @@ function DatePicker<T extends SelectionType>({
45
42
  variant,
46
43
  TextComponent = Text,
47
44
  CalendarComponent,
48
- bottomOffset,
49
45
  rightComponent,
50
- animationType = 'fade',
51
46
  style,
52
47
  locale,
53
48
  closeOnPick = false,
49
+ renderCalendar,
50
+ requestShowCalendar,
51
+ requestCloseCalendar,
54
52
  ...rest
55
53
  }: DatePickerProps<T>): JSX.Element {
54
+
56
55
  const { focused, handleBlur, handleFocus } = useInputFocus(
57
56
  onFocus,
58
57
  onBlur,
59
58
  !disabled
60
59
  );
61
60
 
62
- const [modalVisible, setModalVisible] = React.useState(false);
63
-
64
- const handlePressInput = React.useCallback(() => {
65
- setModalVisible(true);
61
+ const handleShowCalendar = React.useCallback(() => {
62
+ requestShowCalendar()
66
63
  handleFocus();
67
- }, [handleFocus, setModalVisible]);
68
-
69
- const handleCloseModal = React.useCallback(() => {
70
- setModalVisible(false);
71
- handleBlur();
72
- }, [handleBlur, setModalVisible]);
64
+ }, [handleFocus, requestShowCalendar]);
73
65
 
74
66
  const getDisplayValue = () => {
75
67
  if (!value) return placeholder;
@@ -89,23 +81,35 @@ function DatePicker<T extends SelectionType>({
89
81
 
90
82
  useEffect(() => {
91
83
  if (closeOnPick && value && type === 'day') {
92
- setTimeout(handleCloseModal, 200);
84
+ setTimeout(requestCloseCalendar, 200);
93
85
  }
94
86
  if (closeOnPick && value && type === 'range') {
95
87
  const { lowest, highest } = value as DateRange;
96
- lowest && highest && setTimeout(handleCloseModal, 200);
88
+ lowest && highest && setTimeout(requestCloseCalendar, 200);
97
89
  }
98
- }, [value, closeOnPick, type, handleCloseModal]);
90
+ }, [value, closeOnPick, type, requestCloseCalendar]);
91
+
92
+ const calendar = (
93
+ <CalendarComponent
94
+ pointerEvents={'box-none'}
95
+ type={type}
96
+ value={value}
97
+ month={month}
98
+ year={year}
99
+ onChange={onChange}
100
+ locale={locale}
101
+ />
102
+ )
99
103
 
100
104
  return (
101
105
  <>
102
106
  {controlComponent ? (
103
- controlComponent(handlePressInput, getDisplayValue())
107
+ controlComponent(handleShowCalendar, getDisplayValue())
104
108
  ) : (
105
109
  <HintInputContainer
106
110
  focused={focused}
107
111
  viewStyle={style}
108
- onPress={handlePressInput}
112
+ onPress={handleShowCalendar}
109
113
  disabled={disabled}
110
114
  hintComponent={hintComponent}
111
115
  LabelComponent={TextComponent}
@@ -124,20 +128,7 @@ function DatePicker<T extends SelectionType>({
124
128
  </StyledText>
125
129
  </HintInputContainer>
126
130
  )}
127
- <Modal
128
- CalendarComponent={CalendarComponent}
129
- bottomOffset={bottomOffset}
130
- visible={modalVisible}
131
- onRequestClose={handleCloseModal}
132
- animated
133
- animationType={animationType}
134
- month={month}
135
- year={year}
136
- onChange={onChange}
137
- value={value}
138
- type={type}
139
- locale={locale}
140
- />
131
+ {renderCalendar(calendar, handleBlur)}
141
132
  </>
142
133
  );
143
134
  }
@@ -1,50 +1,10 @@
1
1
  import styled, { css } from '@emotion/native';
2
2
  import { FC } from 'react';
3
- import { Platform } from 'react-native';
4
- import { hex2rgba } from '../../../styles/definitions';
5
3
  import { StyleProps } from '../../../types/defaults';
6
- import { RFValue } from '../../../utils';
7
4
  import { Icon } from '../../atoms/Icon';
8
5
  import { disabledInputStyles, InputContainerProps } from '../../atoms/Input';
9
- import { PressableSurface } from '../../atoms/PressableSurface';
10
6
  import { TextProps } from '../../atoms/Text';
11
7
 
12
- const isWeb = Platform.OS === 'web';
13
-
14
- export const Backdrop = styled(PressableSurface)<Partial<StyleProps>>`
15
- ${({ theme }) =>
16
- isWeb
17
- ? css`
18
- justify-content: center;
19
- align-items: center;
20
- background-color: ${hex2rgba(theme.miscellaneous.overlay, 0.5)};
21
- height: 100vh;
22
- `
23
- : css`
24
- justify-content: flex-end;
25
- background-color: ${hex2rgba(theme.miscellaneous.overlay, 0.5)};
26
- height: 100%;
27
- `}
28
- `;
29
-
30
- export const ModalContent = styled.View<
31
- { offset: number } & Partial<StyleProps>
32
- >`
33
- background-color: transparent;
34
- padding-bottom: ${({ offset }) => `${RFValue(offset)}px`};
35
- ${({ theme: { borderRadius } }) => css`
36
- ${isWeb
37
- ? `
38
- border-radius: ${borderRadius.micro};
39
- `
40
- : `
41
- border-top-left-radius: ${borderRadius.deca};
42
- border-top-right-radius: ${borderRadius.deca};
43
- `}
44
- `}
45
- overflow: hidden;
46
- `;
47
-
48
8
  export const getStyledTextComponent = (component: FC<TextProps>) => {
49
9
  return styled(component)(
50
10
  (props: Partial<InputContainerProps> & Partial<StyleProps>) => css`