ripal-ui 1.0.1 → 1.0.2
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 +0 -0
- package/components/BottomSheet.tsx +197 -0
- package/components/Carousel.tsx +61 -0
- package/components/Circle.tsx +44 -0
- package/components/Tab.tsx +90 -0
- package/components/{Table.jsx → Table.tsx} +32 -10
- package/components/index.ts +5 -0
- package/config.js +3 -78
- package/dist/BottomSheet.js +186 -0
- package/dist/Carousel.js +52 -0
- package/dist/Toast.js +72 -0
- package/dist/index.js +74 -12
- package/elements/{Button.jsx → Button.tsx} +51 -26
- package/elements/Dialog.tsx +87 -0
- package/elements/Dropdown.tsx +88 -0
- package/elements/Inline.tsx +38 -0
- package/elements/Input.tsx +75 -0
- package/elements/ProgressBar.tsx +52 -0
- package/elements/Separator.tsx +72 -0
- package/elements/Skeleton.tsx +64 -0
- package/elements/Switch.tsx +64 -0
- package/elements/Text.tsx +73 -0
- package/elements/Toast.tsx +65 -0
- package/elements/Toggle.tsx +59 -0
- package/elements/index.js +2 -1
- package/package.json +6 -3
- package/scripts/generateConfig.js +10 -4
- package/components/Circle.jsx +0 -24
- package/components/Tab.jsx +0 -71
- package/components/index.js +0 -4
- package/elements/Dialog.jsx +0 -64
- package/elements/Dropdown.jsx +0 -66
- package/elements/Inline.jsx +0 -16
- package/elements/Input.jsx +0 -48
- package/elements/ProgressBar.jsx +0 -29
- package/elements/Separator.jsx +0 -32
- package/elements/Skeleton.jsx +0 -50
- package/elements/Switch.jsx +0 -49
- package/elements/Text.jsx +0 -42
- package/elements/Toggle.jsx +0 -48
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { ScrollView, StyleSheet, View } from "react-native";
|
|
3
|
+
import config from "../config";
|
|
4
|
+
import Text from "./Text";
|
|
5
|
+
import Inline from "./Inline";
|
|
6
|
+
import Ionicons from "@expo/vector-icons/Ionicons";
|
|
7
|
+
|
|
8
|
+
type OptionType<T> =
|
|
9
|
+
| T[] // Array of objects
|
|
10
|
+
| string[]; // Array of strings
|
|
11
|
+
|
|
12
|
+
interface DropdownProps<T> {
|
|
13
|
+
options: OptionType<T>;
|
|
14
|
+
value: T | null;
|
|
15
|
+
setValue: (value: T) => void;
|
|
16
|
+
onChange?: (value: T) => void;
|
|
17
|
+
color?: string;
|
|
18
|
+
label?: string | null;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
objectKey?: keyof T | null; // Key for accessing properties if options are objects
|
|
21
|
+
withSearch?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const Dropdown = <T,>({
|
|
25
|
+
options,
|
|
26
|
+
value,
|
|
27
|
+
setValue,
|
|
28
|
+
onChange,
|
|
29
|
+
color = config.colors.primary,
|
|
30
|
+
label = null,
|
|
31
|
+
placeholder = 'Choose',
|
|
32
|
+
objectKey = null,
|
|
33
|
+
withSearch = false,
|
|
34
|
+
}: DropdownProps<T>) => {
|
|
35
|
+
const [isExpanded, setExpanded] = useState(false);
|
|
36
|
+
const isObject = Array.isArray(options) && typeof options[0] === 'object';
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<View style={{ gap: 5 }}>
|
|
40
|
+
{label !== null && <Text size={12} weight="400Regular">{label}</Text>}
|
|
41
|
+
<View style={styles.area}>
|
|
42
|
+
<Inline onPress={() => setExpanded(!isExpanded)}>
|
|
43
|
+
<Text style={{ flexGrow: 1 }}>{value || placeholder}</Text>
|
|
44
|
+
<Ionicons name={isExpanded ? 'chevron-up-outline' : 'chevron-down-outline'} />
|
|
45
|
+
</Inline>
|
|
46
|
+
|
|
47
|
+
{isExpanded && (
|
|
48
|
+
<ScrollView style={{ maxHeight: 200 }}>
|
|
49
|
+
{(options as OptionType<T>).map((opt, o) => {
|
|
50
|
+
const isActive = isObject ? opt[objectKey as keyof T] === value : opt === value;
|
|
51
|
+
const displayValue = isObject ? opt[objectKey as keyof T] : opt;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Inline key={o} style={styles.item} onPress={() => {
|
|
55
|
+
if (onChange) {
|
|
56
|
+
onChange(opt);
|
|
57
|
+
} else {
|
|
58
|
+
setValue(isObject ? opt[objectKey as keyof T] : opt);
|
|
59
|
+
}
|
|
60
|
+
setExpanded(false);
|
|
61
|
+
}}>
|
|
62
|
+
<Text weight={isActive ? '600SemiBold' : '400Regular'} color={isActive ? color : config.colors.slate[500]}>
|
|
63
|
+
{displayValue}
|
|
64
|
+
</Text>
|
|
65
|
+
</Inline>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
</ScrollView>
|
|
69
|
+
)}
|
|
70
|
+
</View>
|
|
71
|
+
</View>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const styles = StyleSheet.create({
|
|
76
|
+
area: {
|
|
77
|
+
padding: 15,
|
|
78
|
+
borderWidth: 1,
|
|
79
|
+
borderColor: config.colors.slate[200],
|
|
80
|
+
borderRadius: 12,
|
|
81
|
+
gap: 15,
|
|
82
|
+
},
|
|
83
|
+
item: {
|
|
84
|
+
height: 40,
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export default Dropdown;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Pressable, PressableProps, StyleSheet, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
interface InlineProps extends PressableProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
|
|
7
|
+
justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
|
|
8
|
+
gap?: number;
|
|
9
|
+
style?: ViewStyle;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Inline: React.FC<InlineProps> = ({
|
|
13
|
+
children,
|
|
14
|
+
alignItems = "center",
|
|
15
|
+
justifyContent = "flex-start",
|
|
16
|
+
gap = 20,
|
|
17
|
+
style,
|
|
18
|
+
onPress,
|
|
19
|
+
onLayout,
|
|
20
|
+
}) => {
|
|
21
|
+
return (
|
|
22
|
+
<Pressable
|
|
23
|
+
style={{
|
|
24
|
+
flexDirection: 'row',
|
|
25
|
+
alignItems,
|
|
26
|
+
justifyContent,
|
|
27
|
+
gap,
|
|
28
|
+
...style,
|
|
29
|
+
}}
|
|
30
|
+
onPress={onPress}
|
|
31
|
+
onLayout={onLayout}
|
|
32
|
+
>
|
|
33
|
+
{children}
|
|
34
|
+
</Pressable>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default Inline;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { View, TextInput, StyleSheet, TextInputProps, ViewStyle } from "react-native";
|
|
3
|
+
import Text from "./Text";
|
|
4
|
+
import Inline from "./Inline";
|
|
5
|
+
import config from "../config";
|
|
6
|
+
|
|
7
|
+
interface InputProps {
|
|
8
|
+
value?: string;
|
|
9
|
+
label?: string | null;
|
|
10
|
+
left?: React.ReactNode | null; // Allows for any valid React node
|
|
11
|
+
right?: React.ReactNode | null; // Allows for any valid React node
|
|
12
|
+
height?: number;
|
|
13
|
+
placeholder?: string | null;
|
|
14
|
+
mode?: TextInputProps["keyboardType"]; // Use keyboardType from TextInputProps
|
|
15
|
+
secureTextEntry?: boolean;
|
|
16
|
+
onChangeText: (text: string) => void; // Function to handle text changes
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const Input: React.FC<InputProps> = ({
|
|
20
|
+
value="",
|
|
21
|
+
label = null,
|
|
22
|
+
left = null,
|
|
23
|
+
right = null,
|
|
24
|
+
height = 50,
|
|
25
|
+
placeholder = null,
|
|
26
|
+
mode = "default",
|
|
27
|
+
secureTextEntry = false,
|
|
28
|
+
onChangeText,
|
|
29
|
+
}) => {
|
|
30
|
+
const [isFocused, setFocused] = useState(false);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<View style={{ gap: 5 }}>
|
|
34
|
+
{label !== null && (
|
|
35
|
+
<Text size={12} weight="400Regular" color={isFocused ? config.colors.primary : config.colors.slate[500]}>
|
|
36
|
+
{label}
|
|
37
|
+
</Text>
|
|
38
|
+
)}
|
|
39
|
+
<Inline
|
|
40
|
+
style={{
|
|
41
|
+
...styles.input,
|
|
42
|
+
borderColor: isFocused ? config.colors.primary : config.colors.slate[200],
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
{left !== null && left}
|
|
46
|
+
<TextInput
|
|
47
|
+
value={value}
|
|
48
|
+
placeholder={placeholder}
|
|
49
|
+
style={{
|
|
50
|
+
height,
|
|
51
|
+
flexGrow: 1,
|
|
52
|
+
}}
|
|
53
|
+
onFocus={() => setFocused(true)}
|
|
54
|
+
onChangeText={onChangeText}
|
|
55
|
+
onBlur={() => setFocused(false)}
|
|
56
|
+
// Using 'default' for generic mode
|
|
57
|
+
keyboardType={mode}
|
|
58
|
+
secureTextEntry={secureTextEntry}
|
|
59
|
+
/>
|
|
60
|
+
{right !== null && right}
|
|
61
|
+
</Inline>
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const styles = StyleSheet.create({
|
|
67
|
+
input: {
|
|
68
|
+
flexGrow: 1,
|
|
69
|
+
borderWidth: 1,
|
|
70
|
+
borderRadius: 12,
|
|
71
|
+
paddingHorizontal: 20,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export default Input;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import { View, StyleSheet, ViewStyle } from "react-native";
|
|
3
|
+
import config from "../config";
|
|
4
|
+
|
|
5
|
+
interface ProgressBarProps {
|
|
6
|
+
value: number;
|
|
7
|
+
from?: number;
|
|
8
|
+
size?: number;
|
|
9
|
+
style?: ViewStyle;
|
|
10
|
+
percentage?: number | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ProgressBar: React.FC<ProgressBarProps> = ({
|
|
14
|
+
value,
|
|
15
|
+
from = 100,
|
|
16
|
+
size = 5,
|
|
17
|
+
style,
|
|
18
|
+
percentage = null,
|
|
19
|
+
}) => {
|
|
20
|
+
const [percent, setPercent] = useState<number | null>(null);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (percent == null) {
|
|
24
|
+
setPercent((value / from) * 100);
|
|
25
|
+
}
|
|
26
|
+
}, [value, from, percent]); // Add dependencies to useEffect
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<View style={{ ...barStyle.area, ...style, height: size }}>
|
|
30
|
+
<View
|
|
31
|
+
style={{
|
|
32
|
+
...barStyle.value,
|
|
33
|
+
width: `${percent !== null ? percent : 0}%`,
|
|
34
|
+
height: size,
|
|
35
|
+
}}
|
|
36
|
+
></View>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const barStyle = StyleSheet.create({
|
|
42
|
+
area: {
|
|
43
|
+
backgroundColor: config.colors.slate[200],
|
|
44
|
+
height: 5,
|
|
45
|
+
flexGrow: 1,
|
|
46
|
+
},
|
|
47
|
+
value: {
|
|
48
|
+
backgroundColor: config.colors.primary,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export default ProgressBar;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Dimensions, StyleSheet, View, ViewStyle } from "react-native";
|
|
3
|
+
import Inline from "./Inline";
|
|
4
|
+
import config from "../config";
|
|
5
|
+
import Text from "./Text";
|
|
6
|
+
|
|
7
|
+
interface SeparatorProps {
|
|
8
|
+
width?: any;
|
|
9
|
+
space?: number;
|
|
10
|
+
height?: number;
|
|
11
|
+
color?: string;
|
|
12
|
+
textProps?: React.ComponentProps<typeof Text>;
|
|
13
|
+
style?: ViewStyle;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Separator: React.FC<SeparatorProps> = ({
|
|
18
|
+
children,
|
|
19
|
+
width = "100%",
|
|
20
|
+
space = 20,
|
|
21
|
+
height = 1,
|
|
22
|
+
color = config.colors.slate[200],
|
|
23
|
+
textProps,
|
|
24
|
+
style,
|
|
25
|
+
}) => {
|
|
26
|
+
let theWidth = width;
|
|
27
|
+
if (typeof width === "string") {
|
|
28
|
+
let toReturn = [];
|
|
29
|
+
let w = width.split("");
|
|
30
|
+
w.map((wi, w) => {
|
|
31
|
+
if (!isNaN(wi)) {
|
|
32
|
+
toReturn.push(wi);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
toReturn = parseInt(toReturn.join(""));
|
|
36
|
+
theWidth = toReturn / 100 * Dimensions.get('screen').width;
|
|
37
|
+
console.log(theWidth);
|
|
38
|
+
}
|
|
39
|
+
return (
|
|
40
|
+
<Inline justifyContent="center">
|
|
41
|
+
<View
|
|
42
|
+
style={{
|
|
43
|
+
backgroundColor: color,
|
|
44
|
+
width: theWidth,
|
|
45
|
+
height: height,
|
|
46
|
+
marginVertical: space,
|
|
47
|
+
...style,
|
|
48
|
+
}}
|
|
49
|
+
></View>
|
|
50
|
+
{children && (
|
|
51
|
+
<Text
|
|
52
|
+
size={12}
|
|
53
|
+
style={{
|
|
54
|
+
position: "absolute",
|
|
55
|
+
backgroundColor: "#fff",
|
|
56
|
+
padding: 10,
|
|
57
|
+
paddingHorizontal: 20,
|
|
58
|
+
}}
|
|
59
|
+
{...textProps}
|
|
60
|
+
>
|
|
61
|
+
{children}
|
|
62
|
+
</Text>
|
|
63
|
+
)}
|
|
64
|
+
</Inline>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const styles = StyleSheet.create({
|
|
69
|
+
// Define your styles here if needed
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export default Separator;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
|
+
import { Animated, StyleSheet, View, ViewStyle } from "react-native";
|
|
3
|
+
import config from "../config";
|
|
4
|
+
|
|
5
|
+
interface SkeletonProps {
|
|
6
|
+
color?: string;
|
|
7
|
+
rounded?: number;
|
|
8
|
+
width?: any;
|
|
9
|
+
height?: number;
|
|
10
|
+
aspectRatio?: number | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Skeleton: React.FC<SkeletonProps> = ({
|
|
14
|
+
color = config.colors.slate[200],
|
|
15
|
+
rounded = 8,
|
|
16
|
+
width = `${Math.floor(Math.random() * (99 - 11 + 1)) + 11}%`,
|
|
17
|
+
height = 20,
|
|
18
|
+
aspectRatio = null,
|
|
19
|
+
}) => {
|
|
20
|
+
const aspectRatioStyles: ViewStyle = { aspectRatio: aspectRatio ?? 1 };
|
|
21
|
+
const heightStyles: ViewStyle = { height: height };
|
|
22
|
+
const opacity = useRef(new Animated.Value(1)).current;
|
|
23
|
+
const defaultStyles: ViewStyle = {
|
|
24
|
+
backgroundColor: color,
|
|
25
|
+
width,
|
|
26
|
+
borderRadius: rounded,
|
|
27
|
+
opacity,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const bounce = () => {
|
|
32
|
+
opacity.setValue(1);
|
|
33
|
+
Animated.timing(opacity, {
|
|
34
|
+
toValue: 0.4,
|
|
35
|
+
duration: 1000,
|
|
36
|
+
useNativeDriver: true,
|
|
37
|
+
}).start(() => {
|
|
38
|
+
Animated.timing(opacity, {
|
|
39
|
+
toValue: 0.8,
|
|
40
|
+
duration: 1000,
|
|
41
|
+
useNativeDriver: true,
|
|
42
|
+
}).start(bounce);
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
bounce();
|
|
47
|
+
}, [opacity]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Animated.View
|
|
51
|
+
style={
|
|
52
|
+
aspectRatio === null
|
|
53
|
+
? [defaultStyles, heightStyles]
|
|
54
|
+
: [defaultStyles, aspectRatioStyles]
|
|
55
|
+
}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const styles = StyleSheet.create({
|
|
61
|
+
// Add your styles here if needed
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export default Skeleton;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Pressable, StyleSheet, View, ViewStyle } from "react-native";
|
|
3
|
+
import config from "../config";
|
|
4
|
+
import Inline from "./Inline";
|
|
5
|
+
|
|
6
|
+
interface SwitchProps {
|
|
7
|
+
active?: boolean;
|
|
8
|
+
size?: number;
|
|
9
|
+
spacer?: number;
|
|
10
|
+
onChange?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Switch: React.FC<SwitchProps> = ({
|
|
14
|
+
active = false,
|
|
15
|
+
size = 24,
|
|
16
|
+
spacer = 5,
|
|
17
|
+
onChange = null,
|
|
18
|
+
}) => {
|
|
19
|
+
const [isActive, setActive] = useState(active);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Pressable
|
|
23
|
+
onPress={() => {
|
|
24
|
+
setActive(!isActive);
|
|
25
|
+
if (onChange) {
|
|
26
|
+
onChange();
|
|
27
|
+
}
|
|
28
|
+
console.log('hehe');
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<Inline
|
|
32
|
+
style={{
|
|
33
|
+
backgroundColor: isActive ? config.colors.green[500] : config.colors.slate[200],
|
|
34
|
+
padding: spacer,
|
|
35
|
+
borderRadius: 999,
|
|
36
|
+
width: size * 2 + spacer + 5,
|
|
37
|
+
}}
|
|
38
|
+
>
|
|
39
|
+
{isActive && <View style={{ flexGrow: 1 }}></View>}
|
|
40
|
+
<View
|
|
41
|
+
style={{
|
|
42
|
+
height: size,
|
|
43
|
+
...styles.circle,
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
{/* Add any inner content here if needed */}
|
|
47
|
+
</View>
|
|
48
|
+
</Inline>
|
|
49
|
+
</Pressable>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const styles = StyleSheet.create({
|
|
54
|
+
area: {
|
|
55
|
+
backgroundColor: config.colors.slate[100],
|
|
56
|
+
},
|
|
57
|
+
circle: {
|
|
58
|
+
backgroundColor: '#fff',
|
|
59
|
+
aspectRatio: 1,
|
|
60
|
+
borderRadius: 9999,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export default Switch;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { FC } from "react";
|
|
2
|
+
import { Text as RNText, TextStyle } from "react-native";
|
|
3
|
+
import { useFonts, Poppins_300Light, Poppins_400Regular, Poppins_500Medium, Poppins_600SemiBold, Poppins_700Bold, Poppins_900Black } from "@expo-google-fonts/poppins";
|
|
4
|
+
import config from "../config";
|
|
5
|
+
|
|
6
|
+
interface TextProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
weight?: '300Light' | '400Regular' | '500Medium' | '600SemiBold' | '700Bold' | '900Black';
|
|
9
|
+
size?: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
align?: 'left' | 'right' | 'center' | 'justify';
|
|
12
|
+
limit?: number;
|
|
13
|
+
spacing?: number;
|
|
14
|
+
lineHeight?: number | null;
|
|
15
|
+
style?: TextStyle;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Text: FC<TextProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
weight = "400Regular",
|
|
21
|
+
size,
|
|
22
|
+
color = config.colors.slate[500],
|
|
23
|
+
align = "left",
|
|
24
|
+
limit = 0,
|
|
25
|
+
spacing = 0,
|
|
26
|
+
lineHeight = null,
|
|
27
|
+
style
|
|
28
|
+
}) => {
|
|
29
|
+
const fontName = "Poppins";
|
|
30
|
+
const [fontsLoaded] = useFonts({
|
|
31
|
+
Poppins_300Light,
|
|
32
|
+
Poppins_400Regular,
|
|
33
|
+
Poppins_500Medium,
|
|
34
|
+
Poppins_600SemiBold,
|
|
35
|
+
Poppins_700Bold,
|
|
36
|
+
Poppins_900Black
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (config.appLangs.default !== null) {
|
|
40
|
+
const ogChildren = children;
|
|
41
|
+
if (typeof children === "string") {
|
|
42
|
+
children = children.split('.').reduce((acc, key) => {
|
|
43
|
+
return acc && acc[key] !== undefined ? acc[key] : ogChildren;
|
|
44
|
+
}, config.appLangs[config.appLangs.default]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!fontsLoaded) {
|
|
49
|
+
return <RNText>{children}</RNText>; // Return statement added to properly handle loading state
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (limit > 0 && typeof children === "string" && children.length > limit) {
|
|
53
|
+
children = children.substr(0, limit) + '...';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<RNText
|
|
58
|
+
style={{
|
|
59
|
+
fontSize: size,
|
|
60
|
+
color: color,
|
|
61
|
+
letterSpacing: spacing,
|
|
62
|
+
lineHeight: lineHeight,
|
|
63
|
+
...style,
|
|
64
|
+
fontFamily: `${fontName}_${weight}`,
|
|
65
|
+
textAlign: align
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{children}
|
|
69
|
+
</RNText>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default Text;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
3
|
+
import Inline from "./Inline";
|
|
4
|
+
import Text from "./Text";
|
|
5
|
+
import config from "../config";
|
|
6
|
+
|
|
7
|
+
interface ToastProps {
|
|
8
|
+
label?: string;
|
|
9
|
+
right?: React.ReactNode; // Allows for any valid React node
|
|
10
|
+
visible?: boolean;
|
|
11
|
+
setVisible: (visible: boolean) => void;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
containerStyle?: ViewStyle; // Style for the container View
|
|
14
|
+
style?: ViewStyle; // Additional style for the Toast
|
|
15
|
+
textProps?: React.ComponentProps<typeof Text>; // Props for the Text component
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Toast: React.FC<ToastProps> = ({
|
|
19
|
+
label = "Percakapan berhasil dihapus",
|
|
20
|
+
right = null,
|
|
21
|
+
visible = true,
|
|
22
|
+
setVisible,
|
|
23
|
+
timeout = 3000,
|
|
24
|
+
containerStyle,
|
|
25
|
+
textProps,
|
|
26
|
+
}) => {
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (visible) {
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
setVisible(false);
|
|
31
|
+
}, timeout);
|
|
32
|
+
|
|
33
|
+
return () => clearTimeout(timer);
|
|
34
|
+
}
|
|
35
|
+
}, [visible, setVisible, timeout]);
|
|
36
|
+
|
|
37
|
+
return visible ? (
|
|
38
|
+
<View style={{ ...styles.container, ...containerStyle }}>
|
|
39
|
+
<Inline style={styles.area}>
|
|
40
|
+
<Text size={12} style={{ flexGrow: 1 }} color="#fff" {...textProps}>
|
|
41
|
+
{label}
|
|
42
|
+
</Text>
|
|
43
|
+
{right}
|
|
44
|
+
</Inline>
|
|
45
|
+
</View>
|
|
46
|
+
) : null;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const styles = StyleSheet.create({
|
|
50
|
+
container: {
|
|
51
|
+
position: 'absolute',
|
|
52
|
+
bottom: 0,
|
|
53
|
+
left: 0,
|
|
54
|
+
right: 0,
|
|
55
|
+
padding: 20,
|
|
56
|
+
},
|
|
57
|
+
area: {
|
|
58
|
+
backgroundColor: config.colors.slate[800],
|
|
59
|
+
borderRadius: 999,
|
|
60
|
+
padding: 20,
|
|
61
|
+
paddingHorizontal: 30,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export default Toast;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Pressable, StyleSheet, View, ViewStyle } from "react-native";
|
|
3
|
+
import config from "../config";
|
|
4
|
+
import Text from "./Text";
|
|
5
|
+
import Inline from "./Inline";
|
|
6
|
+
|
|
7
|
+
interface ToggleProps {
|
|
8
|
+
options: string[];
|
|
9
|
+
value: any;
|
|
10
|
+
setValue: (value: string) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Toggle: React.FC<ToggleProps> = ({ options, value, setValue }) => {
|
|
14
|
+
return (
|
|
15
|
+
<Inline style={styles.area}>
|
|
16
|
+
{options.map((opt, o) => {
|
|
17
|
+
const isActive = value === opt;
|
|
18
|
+
return (
|
|
19
|
+
<Pressable
|
|
20
|
+
key={o}
|
|
21
|
+
style={[styles.item, isActive ? styles.item_active : null]}
|
|
22
|
+
onPress={() => setValue(opt)}
|
|
23
|
+
>
|
|
24
|
+
<Text
|
|
25
|
+
color={isActive ? config.colors.primary : config.colors.slate[500]}
|
|
26
|
+
weight={isActive ? '600SemiBold' : '400Regular'}
|
|
27
|
+
>
|
|
28
|
+
{opt}
|
|
29
|
+
</Text>
|
|
30
|
+
</Pressable>
|
|
31
|
+
);
|
|
32
|
+
})}
|
|
33
|
+
</Inline>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const styles = StyleSheet.create({
|
|
38
|
+
area: {
|
|
39
|
+
padding: 10,
|
|
40
|
+
backgroundColor: config.colors.slate[100],
|
|
41
|
+
borderRadius: 12,
|
|
42
|
+
},
|
|
43
|
+
item: {
|
|
44
|
+
flexGrow: 1,
|
|
45
|
+
flexDirection: 'row',
|
|
46
|
+
alignItems: 'center',
|
|
47
|
+
justifyContent: 'center',
|
|
48
|
+
paddingVertical: 10,
|
|
49
|
+
borderRadius: 12,
|
|
50
|
+
},
|
|
51
|
+
item_active: {
|
|
52
|
+
backgroundColor: '#fff',
|
|
53
|
+
shadowColor: config.colors.slate[300],
|
|
54
|
+
shadowOpacity: 0.4,
|
|
55
|
+
shadowRadius: 12,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export default Toggle;
|
package/elements/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default as Button } from './Button';
|
|
2
|
-
export {
|
|
2
|
+
export { Dialog, DialogActions } from './Dialog';
|
|
3
3
|
export { default as Dropdown } from './Dropdown';
|
|
4
4
|
export { default as Inline } from './Inline';
|
|
5
5
|
export { default as Input } from './Input';
|
|
@@ -8,4 +8,5 @@ export { default as Separator } from './Separator';
|
|
|
8
8
|
export { default as Skeleton } from './Skeleton';
|
|
9
9
|
export { default as Switch } from './Switch';
|
|
10
10
|
export { default as Text } from './Text';
|
|
11
|
+
export { default as Toast } from './Toast';
|
|
11
12
|
export { default as Toggle } from './Toggle';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ripal-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A collection of React elements and components",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,12 +9,15 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"react": "^18.0.0",
|
|
12
|
-
"react-native": "^0.
|
|
12
|
+
"react-native": "^0.74.2"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@babel/cli": "^7.25.6",
|
|
16
16
|
"@babel/core": "^7.25.2",
|
|
17
17
|
"@babel/preset-env": "^7.25.4",
|
|
18
|
-
"@babel/preset-react": "^7.24.7"
|
|
18
|
+
"@babel/preset-react": "^7.24.7",
|
|
19
|
+
"@types/react": "^18.3.10",
|
|
20
|
+
"@types/react-native": "^0.73.0",
|
|
21
|
+
"typescript": "^5.6.2"
|
|
19
22
|
}
|
|
20
23
|
}
|