ripal-ui 1.1.395 → 2.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.
Files changed (70) hide show
  1. package/README.md +3 -0
  2. package/components/Alert.jsx +74 -0
  3. package/components/Avatar.jsx +144 -0
  4. package/components/BottomSheet.jsx +187 -0
  5. package/components/Breadcrumb.jsx +48 -0
  6. package/components/Button.jsx +58 -0
  7. package/components/COLORS.js +138 -0
  8. package/components/Card.jsx +33 -0
  9. package/components/Checkbox.jsx +39 -0
  10. package/components/Dialog.jsx +188 -0
  11. package/components/Divider.jsx +62 -0
  12. package/components/Dropdown.jsx +229 -0
  13. package/components/Grid.jsx +26 -0
  14. package/components/Inline.jsx +37 -0
  15. package/components/Input.jsx +89 -0
  16. package/components/ProgressBar.jsx +65 -0
  17. package/components/Rate.jsx +39 -0
  18. package/components/Slider.jsx +219 -0
  19. package/components/Switch.jsx +45 -0
  20. package/components/Table.jsx +67 -0
  21. package/components/Text.jsx +56 -0
  22. package/components/Toggle.jsx +88 -0
  23. package/index.js +21 -2
  24. package/package.json +19 -23
  25. package/babel.config.js +0 -3
  26. package/components/BottomSheet.tsx +0 -197
  27. package/components/Carousel.tsx +0 -61
  28. package/components/Circle.tsx +0 -44
  29. package/components/DatePicker.jsx +0 -181
  30. package/components/Tab.tsx +0 -90
  31. package/components/Table.tsx +0 -95
  32. package/components/index.ts +0 -5
  33. package/config.js +0 -4
  34. package/dist/BottomSheet.js +0 -186
  35. package/dist/Button.js +0 -109
  36. package/dist/Carousel.js +0 -52
  37. package/dist/Circle.js +0 -42
  38. package/dist/DatePicker.js +0 -199
  39. package/dist/Dialog.js +0 -81
  40. package/dist/Dropdown.js +0 -97
  41. package/dist/Inline.js +0 -38
  42. package/dist/Input.js +0 -88
  43. package/dist/ProgressBar.js +0 -64
  44. package/dist/Separator.js +0 -47
  45. package/dist/Skeleton.js +0 -62
  46. package/dist/Switch.js +0 -74
  47. package/dist/Tab.js +0 -85
  48. package/dist/Table.js +0 -96
  49. package/dist/Text.js +0 -78
  50. package/dist/Toast.js +0 -72
  51. package/dist/Toggle.js +0 -54
  52. package/dist/index.js +0 -96
  53. package/elements/Button.tsx +0 -121
  54. package/elements/ColorPicker.tsx +0 -70
  55. package/elements/Dialog.tsx +0 -87
  56. package/elements/Dropdown.tsx +0 -88
  57. package/elements/Inline.tsx +0 -52
  58. package/elements/Input.tsx +0 -83
  59. package/elements/ProgressBar.tsx +0 -52
  60. package/elements/SecureStorage.js +0 -27
  61. package/elements/Separator.tsx +0 -71
  62. package/elements/Skeleton.tsx +0 -64
  63. package/elements/Slider.tsx +0 -133
  64. package/elements/Switch.tsx +0 -63
  65. package/elements/Text.tsx +0 -73
  66. package/elements/Toast.tsx +0 -71
  67. package/elements/Toggle.tsx +0 -59
  68. package/elements/index.js +0 -14
  69. package/index.d.ts +0 -237
  70. package/scripts/generateConfig.js +0 -80
@@ -0,0 +1,65 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { StyleSheet, View } from "react-native";
3
+ import COLORS from "./COLORS";
4
+ import Text from "./Text";
5
+ import Inline from "./Inline";
6
+
7
+ const ProgressBar = ({value, label = null, displayValue = true, labelPosition = 'left', from = null, color = COLORS.primary, height = 24, radius = 999}) => {
8
+ const [width, setWidth] = useState(0);
9
+
10
+ useEffect(() => {
11
+ if (from === null) {
12
+ setWidth(value);
13
+ } else {
14
+ let percentage = value / from * 100;
15
+ setWidth(percentage);
16
+ }
17
+ }, [value, from]);
18
+
19
+ return (
20
+ <View style={{ gap: 10 }}>
21
+ {
22
+ (label !== null) &&
23
+ <Inline justifyContent={labelPosition?.toLowerCase() === "left" ? 'flex-start' : 'flex-end'}>
24
+ {typeof label === "string" ? <Text>{label}</Text> : label}
25
+ </Inline>
26
+ }
27
+ <View style={[
28
+ styles.container,
29
+ {
30
+ minHeight: height,
31
+ backgroundColor: `${color}20`,
32
+ borderRadius: radius,
33
+ }
34
+ ]}>
35
+ <Inline justifyContent={'flex-end'} style={[
36
+ styles.bar,
37
+ {
38
+ minHeight: height,
39
+ backgroundColor: color,
40
+ borderRadius: radius,
41
+ width: `${width}%`,
42
+ paddingHorizontal: displayValue ? 10 : 0,
43
+ // padding: displayValue ? 5 : 0,
44
+ }
45
+ ]}>
46
+ {
47
+ displayValue &&
48
+ <Text color="#fff" style={{fontWeight: '700'}}>{value}%</Text>
49
+ }
50
+ </Inline>
51
+ </View>
52
+ </View>
53
+ )
54
+ }
55
+
56
+ const styles = StyleSheet.create({
57
+ container: {
58
+ //
59
+ },
60
+ bar: {
61
+ //
62
+ }
63
+ });
64
+
65
+ export default ProgressBar
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import { StyleSheet, TouchableOpacity } from "react-native";
3
+ import Inline from "./Inline";
4
+ import MaterialIcons from "@react-native-vector-icons/material-icons";
5
+ import COLORS from "./COLORS";
6
+
7
+ const Rate = ({rating = 4, setRating = null, icon = null, gap = 5}) => {
8
+ return (
9
+ <Inline gap={gap}>
10
+ {
11
+ [1,1,1,1,1].map((item, i) => {
12
+ let color = i + 1 <= rating ? COLORS.yellow[500] : COLORS.slate[300];
13
+
14
+ if (icon !== null) {
15
+ return icon({
16
+ color
17
+ })
18
+ }
19
+
20
+ return (
21
+ <TouchableOpacity key={i} onPress={() => {
22
+ if (setRating !== null) {
23
+ setRating(i + 1);
24
+ }
25
+ }}>
26
+ <MaterialIcons name="star" size={24} color={color} />
27
+ </TouchableOpacity>
28
+ )
29
+ })
30
+ }
31
+ </Inline>
32
+ )
33
+ }
34
+
35
+ const styles = StyleSheet.create({
36
+ //
37
+ })
38
+
39
+ export default Rate;
@@ -0,0 +1,219 @@
1
+ import MaterialIcons from "@react-native-vector-icons/material-icons";
2
+ import React, { useRef, useState } from "react";
3
+ import { View, StyleSheet, PanResponder } from "react-native";
4
+
5
+ const Slider = ({
6
+ height = 20,
7
+ value = 0,
8
+ range = false,
9
+ onChange = () => {},
10
+ min = 0,
11
+ max = 100,
12
+ thumbRadius = 6,
13
+ }) => {
14
+
15
+ const trackWidth = useRef(0);
16
+
17
+ const [state, setState] = useState(
18
+ range
19
+ ? { min: value[0], max: value[1] }
20
+ : { value }
21
+ );
22
+
23
+ const clamp = (v, minv, maxv) =>
24
+ Math.min(maxv, Math.max(minv, v));
25
+
26
+ const percentToValue = (p) =>
27
+ min + p * (max - min);
28
+
29
+ const valueToPercent = (v) =>
30
+ (v - min) / (max - min);
31
+
32
+ const activeThumb = useRef(null);
33
+
34
+ const updateFromGesture = (x) => {
35
+
36
+ const percent = clamp(x / trackWidth.current, 0, 1);
37
+ const newValue = percentToValue(percent);
38
+
39
+ if (range) {
40
+
41
+ if (activeThumb.current === "min") {
42
+
43
+ const v = clamp(newValue, min, state.max);
44
+
45
+ setState(s => ({ ...s, min: v }));
46
+ onChange([v, state.max]);
47
+
48
+ } else {
49
+
50
+ const v = clamp(newValue, state.min, max);
51
+
52
+ setState(s => ({ ...s, max: v }));
53
+ onChange([state.min, v]);
54
+
55
+ }
56
+
57
+ } else {
58
+
59
+ setState({ value: newValue });
60
+ onChange(newValue);
61
+
62
+ }
63
+
64
+ };
65
+
66
+ const panResponder = useRef(
67
+ PanResponder.create({
68
+
69
+ onStartShouldSetPanResponder: () => true,
70
+ onMoveShouldSetPanResponder: () => true,
71
+
72
+ onPanResponderGrant: (evt) => {
73
+
74
+ const x = evt.nativeEvent.locationX;
75
+
76
+ if (range) {
77
+
78
+ const percent = x / trackWidth.current;
79
+
80
+ const distMin = Math.abs(percent - valueToPercent(state.min));
81
+ const distMax = Math.abs(percent - valueToPercent(state.max));
82
+
83
+ activeThumb.current =
84
+ distMin < distMax ? "min" : "max";
85
+
86
+ } else {
87
+ activeThumb.current = "single";
88
+ }
89
+
90
+ updateFromGesture(x);
91
+
92
+ },
93
+
94
+ onPanResponderMove: (evt) => {
95
+
96
+ updateFromGesture(evt.nativeEvent.locationX);
97
+
98
+ },
99
+
100
+ onPanResponderTerminationRequest: () => false,
101
+ onPanResponderTerminate: () => {},
102
+ onShouldBlockNativeResponder: () => true,
103
+
104
+ })
105
+ ).current;
106
+
107
+ const percentMin = range
108
+ ? valueToPercent(state.min)
109
+ : valueToPercent(state.value);
110
+
111
+ const percentMax = range
112
+ ? valueToPercent(state.max)
113
+ : null;
114
+
115
+ return (
116
+
117
+ <View style={styles.container}>
118
+ <View
119
+ style={[styles.track, { height }]}
120
+ {...panResponder.panHandlers}
121
+ onLayout={(e) => {
122
+ trackWidth.current =
123
+ e.nativeEvent.layout.width;
124
+ }}
125
+ >
126
+
127
+ <View
128
+ style={[
129
+ styles.fill,
130
+ range
131
+ ? {
132
+ left: `${percentMin * 100}%`,
133
+ width: `${(percentMax - percentMin) * 100}%`
134
+ }
135
+ : {
136
+ width: `${percentMin * 100}%`
137
+ }
138
+ ]}
139
+ />
140
+
141
+ <View
142
+ style={[
143
+ styles.thumb,
144
+ {
145
+ left: `${percentMin * 100}%`,
146
+ height: height + 10,
147
+ width: height * 1.25,
148
+ marginLeft: -(height * 0.6),
149
+ borderRadius: thumbRadius
150
+ }
151
+ ]}
152
+ >
153
+ <MaterialIcons
154
+ name="drag-indicator"
155
+ size={height * 0.75}
156
+ color="#888"
157
+ />
158
+ </View>
159
+
160
+ {range && (
161
+ <View
162
+ style={[
163
+ styles.thumb,
164
+ {
165
+ left: `${percentMax * 100}%`,
166
+ height: height + 10,
167
+ width: height * 1.25,
168
+ marginLeft: -(height * 0.6),
169
+ borderRadius: thumbRadius
170
+ }
171
+ ]}
172
+ >
173
+ <MaterialIcons
174
+ name="drag-indicator"
175
+ size={height * 0.75}
176
+ color="#888"
177
+ />
178
+ </View>
179
+ )}
180
+
181
+ </View>
182
+
183
+ </View>
184
+
185
+ );
186
+ };
187
+
188
+ const styles = StyleSheet.create({
189
+
190
+ container: {
191
+ justifyContent: "center"
192
+ },
193
+
194
+ track: {
195
+ width: "100%",
196
+ backgroundColor: "#eee",
197
+ borderRadius: 999,
198
+ justifyContent: "center"
199
+ },
200
+
201
+ fill: {
202
+ position: "absolute",
203
+ height: "100%",
204
+ backgroundColor: "#3b82f6",
205
+ borderRadius: 999
206
+ },
207
+
208
+ thumb: {
209
+ position: "absolute",
210
+ backgroundColor: "#fff",
211
+ borderWidth: 1,
212
+ borderColor: "#ddd",
213
+ alignItems: "center",
214
+ justifyContent: "center"
215
+ }
216
+
217
+ });
218
+
219
+ export default Slider;
@@ -0,0 +1,45 @@
1
+ import React, { useState } from "react";
2
+ import Inline from "./Inline";
3
+ import { StyleSheet, View } from "react-native";
4
+ import COLORS from "./COLORS";
5
+ import Text from "./Text";
6
+
7
+ const Switch = ({active, setActive, size = 24}) => {
8
+
9
+ return (
10
+ <Inline>
11
+ <Inline style={[
12
+ styles.container,
13
+ {
14
+ width: ((size + 15) * 2) - 5,
15
+ backgroundColor: active ? COLORS.green[500] : COLORS.gray[300]
16
+ }
17
+ ]} justifyContent={active ? 'flex-end' : 'flex-start'} onPress={() => {
18
+ setActive(!active);
19
+ }}>
20
+ <View style={[
21
+ styles.btn,
22
+ {
23
+ height: size,
24
+ width: size + 15,
25
+ }
26
+ ]} />
27
+ </Inline>
28
+ </Inline>
29
+ )
30
+ }
31
+
32
+ const styles = StyleSheet.create({
33
+ container: {
34
+ backgroundColor: COLORS.slate[200],
35
+ padding: 5,
36
+ borderRadius: 999,
37
+ },
38
+ btn: {
39
+ width: '100%',
40
+ backgroundColor: '#fff',
41
+ borderRadius: 99,
42
+ }
43
+ })
44
+
45
+ export default Switch;
@@ -0,0 +1,67 @@
1
+ import React, { createContext, useContext, useState } from "react";
2
+ import { ScrollView, StyleSheet, View } from "react-native";
3
+ import Text from "./Text";
4
+ import Inline from "./Inline";
5
+ import COLORS from "./COLORS";
6
+
7
+ const TableContext = createContext(null);
8
+ const useTable = () => {
9
+ const ctx = useContext(TableContext);
10
+ if (!ctx) throw new Error("Table subcomponents must be used inside Table");
11
+ return ctx;
12
+ };
13
+
14
+ const Table = ({ children, colsWidth }) => {
15
+ const [width, setWidth] = useState(0);
16
+
17
+ return (
18
+ <TableContext.Provider value={{
19
+ colsWidth: colsWidth ?? [],
20
+ width,
21
+ }}>
22
+ <ScrollView showsHorizontalScrollIndicator={false} horizontal style={{height: 'auto'}} contentContainerStyle={{ flexDirection: 'column', height: 'auto' }} onLayout={e => {
23
+ setWidth(e.nativeEvent.layout.width);
24
+ }}>
25
+ {children}
26
+ </ScrollView>
27
+ </TableContext.Provider>
28
+ )
29
+ }
30
+
31
+ Table.Row = ({ children, isHeader }) => {
32
+ const { colsWidth } = useTable();
33
+
34
+ return (
35
+ <Inline style={{
36
+ ...styles.row,
37
+ backgroundColor: isHeader ? COLORS.slate[200] : '#ffffff00'
38
+ }}>
39
+ {children}
40
+ </Inline>
41
+ )
42
+ }
43
+ Table.Cell = ({ children, index }) => {
44
+ const { colsWidth, width } = useTable();
45
+
46
+ return (
47
+ <View style={{
48
+ width: colsWidth[index] ?? 'auto',
49
+ }}>
50
+ { typeof children === "string" ?
51
+ <Text>{children}</Text>
52
+ : children
53
+ }
54
+ </View>
55
+ )
56
+ }
57
+
58
+ const styles = StyleSheet.create({
59
+ row: {
60
+ padding: 10,
61
+ paddingHorizontal: 20,
62
+ borderRadius: 8,
63
+ }
64
+ })
65
+
66
+
67
+ export default Table;
@@ -0,0 +1,56 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Text as RNText } from "react-native";
3
+ import COLORS from "./COLORS";
4
+
5
+ const Text = ({ children, style, size, align, limit, spacing, lineHeight = null, color = COLORS.stone[600] }) => {
6
+ const [toRender, setToRender] = useState(children);
7
+
8
+ useEffect(() => {
9
+ if (!limit) {
10
+ setToRender(children);
11
+ return;
12
+ }
13
+
14
+ if (typeof children !== "string") {
15
+ setToRender(children);
16
+ return;
17
+ }
18
+
19
+ let truncated = children;
20
+ let isTruncated = false;
21
+
22
+ if (typeof limit === "number") {
23
+ if (children.length > limit) {
24
+ truncated = children.substring(0, limit);
25
+ isTruncated = true;
26
+ }
27
+ } else if (typeof limit === "object" && limit.count) {
28
+ const words = children.split(" ");
29
+ if (words.length > limit.count) {
30
+ truncated = words.slice(0, limit.count).join(" ");
31
+ isTruncated = true;
32
+ }
33
+ }
34
+
35
+ setToRender(isTruncated ? truncated + "..." : truncated);
36
+ }, [children, limit]);
37
+
38
+ return (
39
+ <RNText
40
+ style={[
41
+ {
42
+ fontSize: size,
43
+ textAlign: align,
44
+ lineHeight: lineHeight ?? undefined,
45
+ letterSpacing: spacing ?? undefined,
46
+ color,
47
+ },
48
+ style
49
+ ]}
50
+ >
51
+ {toRender}
52
+ </RNText>
53
+ );
54
+ };
55
+
56
+ export default Text;
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import { StyleSheet, TouchableOpacity } from "react-native";
3
+ import Inline from "./Inline";
4
+ import COLORS from "./COLORS";
5
+ import Text from "./Text";
6
+
7
+ const Toggle = ({ options = [], value = null, setValue, onChange, objectKey = null }) => {
8
+
9
+ const getOptionValue = (opt) => {
10
+ if (objectKey && typeof opt === 'object') {
11
+ return opt[objectKey];
12
+ }
13
+ return opt;
14
+ };
15
+
16
+ const isActive = (opt, index) => {
17
+ if (value === null) {
18
+ return index === 0;
19
+ }
20
+
21
+ // compare primitive directly
22
+ if (typeof opt !== 'object') {
23
+ return value === opt;
24
+ }
25
+
26
+ // compare object by key
27
+ if (objectKey) {
28
+ return value?.[objectKey] === opt?.[objectKey];
29
+ }
30
+
31
+ // fallback: strict reference
32
+ return value === opt;
33
+ };
34
+
35
+ const handlePress = (opt) => {
36
+ setValue?.(opt);
37
+ onChange?.(opt);
38
+ };
39
+
40
+ return (
41
+ <Inline>
42
+ <Inline gap={0} style={styles.area}>
43
+ {options.map((opt, index) => {
44
+
45
+ const active = isActive(opt, index);
46
+
47
+ return (
48
+ <TouchableOpacity
49
+ key={index}
50
+ onPress={() => handlePress(opt)}
51
+ style={[
52
+ styles.item,
53
+ active && styles.item_active
54
+ ]}
55
+ >
56
+ <Text size={13} color={active ? COLORS.primary : COLORS.slate[500]} style={{fontWeight: active ? '700' : '400'}}>
57
+ {getOptionValue(opt)}
58
+ </Text>
59
+ </TouchableOpacity>
60
+ );
61
+
62
+ })}
63
+ </Inline>
64
+ </Inline>
65
+ );
66
+ };
67
+
68
+ const styles = StyleSheet.create({
69
+ area: {
70
+ borderRadius: 999,
71
+ backgroundColor: COLORS.slate[100],
72
+ padding: 5,
73
+ },
74
+ item: {
75
+ padding: 10,
76
+ paddingHorizontal: 20,
77
+ borderRadius: 99,
78
+ },
79
+ item_active: {
80
+ backgroundColor: '#fff',
81
+ shadowColor: '#ddd',
82
+ shadowOpacity: 0.8,
83
+ shadowOffset: { width: 1, height: 1},
84
+ shadowRadius: 10,
85
+ }
86
+ });
87
+
88
+ export default Toggle;
package/index.js CHANGED
@@ -1,2 +1,21 @@
1
- export * from './elements';
2
- export * from './components';
1
+ export { default as Alert } from "./components/Alert";
2
+ export { default as Avatar } from "./components/Avatar";
3
+ export { default as BottomSheet } from "./components/BottomSheet";
4
+ export { default as Breadcrumb } from "./components/Breadcrumb";
5
+ export { default as Button } from "./components/Button";
6
+ export { default as Card } from "./components/Card";
7
+ export { default as Checkbox } from "./components/Checkbox";
8
+ export { default as COLORS } from "./components/COLORS";
9
+ export { default as Dialog } from "./components/Dialog";
10
+ export { default as Divider } from "./components/Divider";
11
+ export { default as Dropdown } from "./components/Dropdown";
12
+ export { default as Grid } from "./components/Grid";
13
+ export { default as Inline } from "./components/Inline";
14
+ export { default as Input } from "./components/Input";
15
+ export { default as ProgressBar } from "./components/ProgressBar";
16
+ export { default as Rate } from "./components/Rate";
17
+ export { default as Slider } from "./components/Slider";
18
+ export { default as Switch } from "./components/Switch";
19
+ export { default as Table } from "./components/Table";
20
+ export { default as Text } from "./components/Text";
21
+ export { default as Toggle } from "./components/Toggle";
package/package.json CHANGED
@@ -1,28 +1,24 @@
1
1
  {
2
2
  "name": "ripal-ui",
3
- "version": "1.1.395",
4
- "description": "A collection of React elements and components",
3
+ "version": "2.0.2",
4
+ "description": "Reusable React Native UI components",
5
5
  "main": "index.js",
6
- "types": "index.d.ts",
7
- "scripts": {
8
- "build": "babel elements components --out-dir dist",
9
- "postinstall": "node ./scripts/generateConfig.js"
10
- },
11
- "dependencies": {
12
- "expo-secure-store": "~15.0.7",
13
- "react": "^19.1.0",
14
- "react-native": "^0.81.5"
15
- },
6
+ "react-native": "index.js",
7
+ "files": [
8
+ "components",
9
+ "index.js"
10
+ ],
11
+ "keywords": [
12
+ "react-native",
13
+ "ui",
14
+ "components"
15
+ ],
16
+ "author": "Your Name",
17
+ "license": "MIT",
18
+
16
19
  "peerDependencies": {
17
- "@expo-google-fonts/poppins": ">=0.3.0",
18
- "expo-font": ">=11.0.0"
19
- },
20
- "devDependencies": {
21
- "@babel/cli": "^7.25.6",
22
- "@babel/core": "^7.25.2",
23
- "@babel/preset-env": "^7.25.4",
24
- "@babel/preset-react": "^7.24.7",
25
- "@types/react": "^19.0.0",
26
- "typescript": "^5.6.2"
20
+ "react": ">=18",
21
+ "react-native": ">=0.70",
22
+ "@react-native-vector-icons/material-icons": ">=12"
27
23
  }
28
- }
24
+ }
package/babel.config.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- presets: ['@babel/preset-env', '@babel/preset-react']
3
- };