@herca/rn-kit 0.1.63 → 0.1.65
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.
- package/README.md +8 -0
- package/lib/module/DatePicker/DatePicker.js +2 -2
- package/lib/module/DatePicker/DatePicker.js.map +1 -1
- package/lib/module/Input/InputDate.js +170 -0
- package/lib/module/Input/InputDate.js.map +1 -0
- package/lib/module/Input/README_INPUT_DATE.md +265 -0
- package/lib/module/Modal/Modal.js +24 -22
- package/lib/module/Modal/Modal.js.map +1 -1
- package/lib/module/Ui/README_VIEWINSETS.md +126 -0
- package/lib/module/Ui/ViewInsets.js +33 -0
- package/lib/module/Ui/ViewInsets.js.map +1 -0
- package/lib/module/function/README_DATE_FORMATTER.md +397 -0
- package/lib/module/function/dateFormatter.js +38 -0
- package/lib/module/function/dateFormatter.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/Calendar/CalendarPropsType.d.ts +5 -0
- package/lib/typescript/src/Calendar/CalendarPropsType.d.ts.map +1 -1
- package/lib/typescript/src/Input/InputDate.d.ts +27 -0
- package/lib/typescript/src/Input/InputDate.d.ts.map +1 -0
- package/lib/typescript/src/Modal/Modal.d.ts.map +1 -1
- package/lib/typescript/src/Ui/ViewInsets.d.ts +13 -0
- package/lib/typescript/src/Ui/ViewInsets.d.ts.map +1 -0
- package/lib/typescript/src/function/dateFormatter.d.ts +14 -0
- package/lib/typescript/src/function/dateFormatter.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Calendar/CalendarPropsType.tsx +6 -0
- package/src/DatePicker/DatePicker.tsx +2 -2
- package/src/Input/InputDate.tsx +216 -0
- package/src/Input/README_INPUT_DATE.md +265 -0
- package/src/Modal/Modal.tsx +31 -46
- package/src/Ui/README_VIEWINSETS.md +126 -0
- package/src/Ui/ViewInsets.tsx +46 -0
- package/src/function/README_DATE_FORMATTER.md +397 -0
- package/src/function/dateFormatter.ts +54 -0
- package/src/index.tsx +8 -1
package/src/Modal/Modal.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Color, Icon } from '@herca/rn-kit';
|
|
1
2
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
View,
|
|
@@ -10,8 +11,6 @@ import {
|
|
|
10
11
|
Platform,
|
|
11
12
|
type ViewStyle,
|
|
12
13
|
} from 'react-native';
|
|
13
|
-
import Icon from '../Icon';
|
|
14
|
-
import Color from '../Color/Color';
|
|
15
14
|
|
|
16
15
|
interface ModalPopUpProps {
|
|
17
16
|
isOpen: boolean;
|
|
@@ -39,11 +38,10 @@ const ModalPopUp: React.FC<ModalPopUpProps> = ({
|
|
|
39
38
|
containerStyle,
|
|
40
39
|
modalStyle,
|
|
41
40
|
}) => {
|
|
42
|
-
const [isVisible, setIsVisible] = useState(isOpen);
|
|
41
|
+
const [isVisible, setIsVisible] = useState(isOpen ?? false);
|
|
43
42
|
const scaleAnim = useState(() => new Animated.Value(0))[0];
|
|
44
43
|
|
|
45
|
-
const
|
|
46
|
-
setIsVisible(true);
|
|
44
|
+
const animateIn = useCallback(() => {
|
|
47
45
|
Animated.spring(scaleAnim, {
|
|
48
46
|
toValue: 1,
|
|
49
47
|
useNativeDriver: true,
|
|
@@ -52,24 +50,31 @@ const ModalPopUp: React.FC<ModalPopUpProps> = ({
|
|
|
52
50
|
}).start();
|
|
53
51
|
}, [scaleAnim]);
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (isOpen) {
|
|
55
|
+
setIsVisible(true);
|
|
56
|
+
animateIn();
|
|
57
|
+
} else if (isVisible) {
|
|
58
|
+
setIsVisible(false);
|
|
59
|
+
onRequestClose?.();
|
|
60
|
+
onClose?.();
|
|
61
|
+
}
|
|
62
|
+
}, [isOpen, isVisible, animateIn, onRequestClose, onClose]);
|
|
63
|
+
|
|
64
|
+
const userClose = useCallback(() => {
|
|
65
|
+
if (!closable) return;
|
|
56
66
|
setIsVisible(false);
|
|
57
67
|
onRequestClose?.();
|
|
58
68
|
onClose?.();
|
|
59
|
-
}, [onClose, onRequestClose]);
|
|
69
|
+
}, [closable, onClose, onRequestClose]);
|
|
60
70
|
|
|
61
|
-
const handleBackdropPress =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
}, [closable, hideModal]);
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
if (isOpen) {
|
|
68
|
-
showModal();
|
|
69
|
-
}
|
|
71
|
+
const handleBackdropPress = () => {
|
|
72
|
+
userClose();
|
|
73
|
+
};
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
const handleRequestClose = () => {
|
|
76
|
+
userClose();
|
|
77
|
+
};
|
|
73
78
|
|
|
74
79
|
const modalContentStyle = StyleSheet.flatten([
|
|
75
80
|
{
|
|
@@ -85,7 +90,7 @@ const ModalPopUp: React.FC<ModalPopUpProps> = ({
|
|
|
85
90
|
<Modal
|
|
86
91
|
transparent
|
|
87
92
|
visible={isVisible}
|
|
88
|
-
onRequestClose={
|
|
93
|
+
onRequestClose={handleRequestClose}
|
|
89
94
|
statusBarTranslucent
|
|
90
95
|
>
|
|
91
96
|
<View style={[styles.modalContainer, containerStyle]}>
|
|
@@ -99,7 +104,7 @@ const ModalPopUp: React.FC<ModalPopUpProps> = ({
|
|
|
99
104
|
<Animated.View style={[styles.modalContent, modalContentStyle]}>
|
|
100
105
|
{closable && (
|
|
101
106
|
<View style={styles.closeButtonContainer}>
|
|
102
|
-
<TouchableOpacity onPress={
|
|
107
|
+
<TouchableOpacity onPress={userClose} style={styles.closeButton}>
|
|
103
108
|
<View style={styles.iconButtonClose}>
|
|
104
109
|
<Icon name="Times" size={13} color={Color.gray[900]} />
|
|
105
110
|
</View>
|
|
@@ -116,11 +121,7 @@ const ModalPopUp: React.FC<ModalPopUpProps> = ({
|
|
|
116
121
|
};
|
|
117
122
|
|
|
118
123
|
const styles = StyleSheet.create({
|
|
119
|
-
modalContainer: {
|
|
120
|
-
flex: 1,
|
|
121
|
-
justifyContent: 'center',
|
|
122
|
-
alignItems: 'center',
|
|
123
|
-
},
|
|
124
|
+
modalContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' },
|
|
124
125
|
backdrop: {
|
|
125
126
|
position: 'absolute',
|
|
126
127
|
top: 0,
|
|
@@ -129,39 +130,25 @@ const styles = StyleSheet.create({
|
|
|
129
130
|
bottom: 0,
|
|
130
131
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
131
132
|
},
|
|
132
|
-
backdropTouch: {
|
|
133
|
-
width: '100%',
|
|
134
|
-
height: '100%',
|
|
135
|
-
},
|
|
133
|
+
backdropTouch: { width: '100%', height: '100%' },
|
|
136
134
|
modalContent: {
|
|
137
135
|
borderRadius: 16,
|
|
138
136
|
overflow: 'visible',
|
|
139
137
|
...Platform.select({
|
|
140
138
|
ios: {
|
|
141
139
|
shadowColor: '#000',
|
|
142
|
-
shadowOffset: {
|
|
143
|
-
width: 0,
|
|
144
|
-
height: 2,
|
|
145
|
-
},
|
|
140
|
+
shadowOffset: { width: 0, height: 2 },
|
|
146
141
|
shadowOpacity: 0.25,
|
|
147
142
|
shadowRadius: 4,
|
|
148
143
|
},
|
|
149
|
-
android: {
|
|
150
|
-
elevation: 5,
|
|
151
|
-
},
|
|
144
|
+
android: { elevation: 5 },
|
|
152
145
|
}),
|
|
153
146
|
},
|
|
154
|
-
closeButtonContainer: {
|
|
155
|
-
position: 'absolute',
|
|
156
|
-
top: 10,
|
|
157
|
-
right: 10,
|
|
158
|
-
zIndex: 1,
|
|
159
|
-
},
|
|
147
|
+
closeButtonContainer: { position: 'absolute', top: 10, right: 10, zIndex: 1 },
|
|
160
148
|
iconButtonClose: {
|
|
161
149
|
justifyContent: 'center',
|
|
162
150
|
alignContent: 'center',
|
|
163
151
|
alignItems: 'center',
|
|
164
|
-
top: 'auto',
|
|
165
152
|
flex: 1,
|
|
166
153
|
},
|
|
167
154
|
closeButton: {
|
|
@@ -170,9 +157,7 @@ const styles = StyleSheet.create({
|
|
|
170
157
|
borderRadius: 12,
|
|
171
158
|
backgroundColor: '#ccc',
|
|
172
159
|
},
|
|
173
|
-
contentContainer: {
|
|
174
|
-
padding: 16,
|
|
175
|
-
},
|
|
160
|
+
contentContainer: { padding: 16 },
|
|
176
161
|
});
|
|
177
162
|
|
|
178
163
|
export default ModalPopUp;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# ViewInsets Component
|
|
2
|
+
|
|
3
|
+
Komponen React Native yang menyediakan padding otomatis berdasarkan safe area insets untuk menghindari area sistem seperti notch, status bar, dan navigation bar.
|
|
4
|
+
|
|
5
|
+
## Instalasi
|
|
6
|
+
|
|
7
|
+
Komponen ini membutuhkan dependency berikut:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install react-native-safe-area-context
|
|
11
|
+
# atau
|
|
12
|
+
yarn add react-native-safe-area-context
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Pastikan untuk membungkus aplikasi Anda dengan `SafeAreaProvider`:
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return <SafeAreaProvider>{/* Konten aplikasi Anda */}</SafeAreaProvider>;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Penggunaan Dasar
|
|
26
|
+
|
|
27
|
+
```jsx
|
|
28
|
+
import ViewInsets from './ViewInsets';
|
|
29
|
+
|
|
30
|
+
function MyScreen() {
|
|
31
|
+
return (
|
|
32
|
+
<ViewInsets useTop useBottom>
|
|
33
|
+
{/* Konten Anda */}
|
|
34
|
+
</ViewInsets>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Props
|
|
40
|
+
|
|
41
|
+
| Prop | Type | Default | Deskripsi |
|
|
42
|
+
| ----------- | ---------------------- | ------------ | ------------------------------------------------------- |
|
|
43
|
+
| `children` | `React.ReactNode` | **Required** | Konten yang akan ditampilkan di dalam container |
|
|
44
|
+
| `useTop` | `boolean` | `false` | Menambahkan padding top sesuai safe area inset atas |
|
|
45
|
+
| `useBottom` | `boolean` | `false` | Menambahkan padding bottom sesuai safe area inset bawah |
|
|
46
|
+
| `useLeft` | `boolean` | `false` | Menambahkan padding left sesuai safe area inset kiri |
|
|
47
|
+
| `useRight` | `boolean` | `false` | Menambahkan padding right sesuai safe area inset kanan |
|
|
48
|
+
| `style` | `StyleProp<ViewStyle>` | `undefined` | Style tambahan untuk container |
|
|
49
|
+
| `...rest` | `ViewProps` | - | Props lainnya akan diteruskan ke komponen View |
|
|
50
|
+
|
|
51
|
+
## Contoh Penggunaan
|
|
52
|
+
|
|
53
|
+
### Layar dengan Safe Area Atas dan Bawah
|
|
54
|
+
|
|
55
|
+
```jsx
|
|
56
|
+
<ViewInsets useTop useBottom>
|
|
57
|
+
<Text>Konten aman dari notch dan navigation bar</Text>
|
|
58
|
+
</ViewInsets>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Layar dengan Safe Area Atas Saja
|
|
62
|
+
|
|
63
|
+
```jsx
|
|
64
|
+
<ViewInsets useTop>
|
|
65
|
+
<Text>Konten aman dari status bar/notch</Text>
|
|
66
|
+
</ViewInsets>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Layar dengan Safe Area di Semua Sisi
|
|
70
|
+
|
|
71
|
+
```jsx
|
|
72
|
+
<ViewInsets useTop useBottom useLeft useRight>
|
|
73
|
+
<Text>Konten aman dari semua area sistem</Text>
|
|
74
|
+
</ViewInsets>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Dengan Custom Style
|
|
78
|
+
|
|
79
|
+
```jsx
|
|
80
|
+
<ViewInsets
|
|
81
|
+
useTop
|
|
82
|
+
useBottom
|
|
83
|
+
style={{ backgroundColor: '#fff', paddingHorizontal: 16 }}
|
|
84
|
+
>
|
|
85
|
+
<Text>Konten dengan style tambahan</Text>
|
|
86
|
+
</ViewInsets>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Dengan Props View Lainnya
|
|
90
|
+
|
|
91
|
+
```jsx
|
|
92
|
+
<ViewInsets useTop useBottom testID="main-container" accessible={true}>
|
|
93
|
+
<Text>Konten dengan props accessibility</Text>
|
|
94
|
+
</ViewInsets>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Fitur
|
|
98
|
+
|
|
99
|
+
- ✅ Otomatis menangani safe area insets
|
|
100
|
+
- ✅ Kontrol granular untuk setiap sisi (atas, bawah, kiri, kanan)
|
|
101
|
+
- ✅ Performa optimal dengan `useMemo` untuk menghindari re-render tidak perlu
|
|
102
|
+
- ✅ Mendukung semua props dari komponen View React Native
|
|
103
|
+
- ✅ TypeScript support dengan type definitions lengkap
|
|
104
|
+
- ✅ Default `flex: 1` untuk kemudahan layout
|
|
105
|
+
|
|
106
|
+
## Catatan
|
|
107
|
+
|
|
108
|
+
- Komponen ini secara default menggunakan `flex: 1` pada container
|
|
109
|
+
- Safe area insets akan disesuaikan secara otomatis berdasarkan perangkat
|
|
110
|
+
- Berguna untuk menghindari area yang tertutup oleh notch, status bar, home indicator, dll
|
|
111
|
+
- Dapat dikombinasikan dengan style custom untuk kebutuhan layout yang lebih kompleks
|
|
112
|
+
|
|
113
|
+
## TypeScript
|
|
114
|
+
|
|
115
|
+
Komponen ini sudah dilengkapi dengan TypeScript definitions. Interface `ViewInsetsProps` extends dari `ViewProps` sehingga mendukung semua props dari View React Native.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
interface ViewInsetsProps extends ViewProps {
|
|
119
|
+
children: React.ReactNode;
|
|
120
|
+
useTop?: boolean;
|
|
121
|
+
useBottom?: boolean;
|
|
122
|
+
useLeft?: boolean;
|
|
123
|
+
useRight?: boolean;
|
|
124
|
+
bottomType?: 'inset' | 'tabbar'; // Prop ini didefinisikan tapi belum diimplementasikan
|
|
125
|
+
}
|
|
126
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { StyleSheet, View, type ViewProps } from 'react-native';
|
|
2
|
+
import React, { useMemo } from 'react';
|
|
3
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
|
|
5
|
+
interface ViewInsetsProps extends ViewProps {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
useTop?: boolean;
|
|
8
|
+
useBottom?: boolean;
|
|
9
|
+
useLeft?: boolean;
|
|
10
|
+
useRight?: boolean;
|
|
11
|
+
bottomType?: 'inset' | 'tabbar';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ViewInsets: React.FC<ViewInsetsProps> = ({
|
|
15
|
+
children,
|
|
16
|
+
style,
|
|
17
|
+
useTop = false,
|
|
18
|
+
useBottom = false,
|
|
19
|
+
useLeft = false,
|
|
20
|
+
useRight = false,
|
|
21
|
+
...rest
|
|
22
|
+
}) => {
|
|
23
|
+
const insets = useSafeAreaInsets();
|
|
24
|
+
|
|
25
|
+
const defaultStyle = useMemo(
|
|
26
|
+
() =>
|
|
27
|
+
StyleSheet.create({
|
|
28
|
+
container: {
|
|
29
|
+
paddingTop: useTop ? insets.top : 0,
|
|
30
|
+
paddingBottom: useBottom ? insets.bottom : 0,
|
|
31
|
+
paddingLeft: useLeft ? insets.left : 0,
|
|
32
|
+
paddingRight: useRight ? insets.right : 0,
|
|
33
|
+
flex: 1,
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
[insets, useTop, useBottom, useLeft, useRight]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<View style={[defaultStyle.container, style]} {...rest}>
|
|
41
|
+
{children}
|
|
42
|
+
</View>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default ViewInsets;
|